home *** CD-ROM | disk | FTP | other *** search
Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
- #! /bin/sh
- # Copyright (c) 1991-1993, Anastasios C. Kotsikonas
- #
- touch setup systest upgrade_to_6.0c; chmod 700 setup systest upgrade_to_6.0c
- #!/bin/sh
- # Determine how echo suppresses new-line
- echo "a\c" > /tmp/echo
- if [ "`grep c /tmp/echo`" = "a\c" ]; then
- n='-n'
- c=''
- else
- n=''
- c='\c'
- fi
- rm /tmp/echo
-
- echo
- echo \ \ \ ListProcessor 6.0
- echo \ \ \ -----------------
- echo
- if [ -d osrc -o -d ohelp -o -d oarchives -o -f oconfig -o -f o.ignored \
- -o -f oowners -o -f ounwanted.hosts -o -f opriv.hosts -o -d outil \
- -o -f owelcome.live ]; then
- echo Old system image found:
- echo
- ls -CFd o[a-w\.]*
- echo
- echo The current system will be moved to files/dirs starting with \'o\'
- echo as shown above and confirmation is required to remove that old image.
- echo $n "Proceed [y]? $c"
- read x
- if [ "$x" = "n" -o "$x" = "N" ]; then
- exit 0
- fi
- fi
- if [ -d src ]; then
- echo WARNING: Moving src/ to osrc/
- rm -rf osrc
- rmdir osrc > /dev/null 2>&1
- mv src osrc
- fi
- if [ ! -d src ]; then
- mkdir src
- fi
- if [ ! -d src/ansi ]; then
- mkdir src/ansi
- fi
- if [ ! -d src/nonansi ]; then
- mkdir src/nonansi
- fi
- if [ ! -d gateway ]; then
- mkdir gateway
- fi
- if [ ! -d doc ]; then
- mkdir doc
- fi
- if [ -d help ]; then
- echo WARNING: Moving help/ to ohelp/
- rm -rf ohelp
- rmdir ohelp > /dev/null 2>&1
- mv help ohelp
- fi
- mkdir help
- if [ -d util ]; then
- echo WARNING: Moving util/ to outil/
- rm -rf outil
- rmdir outil > /dev/null 2>&1
- mv util outil
- fi
- mkdir util
- if [ -d archives ]; then
- echo WARNING: Moving archives/ to oarchives/
- rm -rf oarchives
- rmdir oarchives > /dev/null 2>&1
- mv archives oarchives
- fi
- mkdir archives
- mkdir archives/listproc
- mkdir archives/listproc/example.dat
- mkdir archives/pub
- mkdir archives/pub/unix
- mkdir archives/pub/private
- mkdir archives/unix
- mkdir archives/ilp
- if [ -f config ]; then
- echo WARNING: Moving config to oconfig
- mv config oconfig
- fi
- if [ -f owners ]; then
- echo WARNING: Moving owners to oowners
- mv owners oowners
- fi
- if [ -f .ignored ]; then
- echo WARNING: Moving .ignored to o.ignored
- mv .ignored o.ignored
- fi
- if [ -f unwanted.hosts ]; then
- echo WARNING: Moving unwanted.hosts to ounwanted.hosts
- mv unwanted.hosts ounwanted.hosts
- fi
- if [ -f welcome.live ]; then
- echo WARNING: Moving welcome.live to owelcome.live
- mv welcome.live owelcome.live
- fi
- echo x - src/README
- sed 's/^X//' >src/README <<'*-*-END-of-src/README-*-*'
- X
- X
- X LISTPROCESSOR SYSTEM
- X --------------------
- X
- X Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X
- X tasos@cs.bu.edu
- X July 1 1993
- X
- XDESCRIPTION:
- X This is a system that implements various mailing lists with
- X one list manager. It is automated, and obliterates the need
- X for user intervention and maintenance of multiple aliases of
- X the form "list, list-owner, list-request", etc. There is
- X support provided for public and private hierarchical
- X archives, moderated and non-moderated lists, peer lists,
- X peer servers, private lists, address aliasing, news connec-
- X tions and gateways, mail queueing, digests, list ownership,
- X owner preferences, crash recovery, batch processing, confi-
- X gurable headers, regular expressions, archive searching, and
- X live user connections via TCP/IP.
- X
- XCOPYING: You may distribute the software freely, but you may not include
- Xany part of the code in a commercial application whatsoever, directly or by
- Ximplication. Modified code may NOT be distributed.
- X
- XAGREEMENT: This software can be used and distributed freely only as a
- Xwhole and not in parts, as long as you do not remove or alter the author
- Xand copyright notices in the file defs.h; this notices are #define'd in
- Xthe symbols VERSION and COPYRIGHT. Although you may alter the code
- Xprovided for your personal use, you may not alter the functions
- Xcreate_header(), create_multi_recipient_header() and main() in list.c,
- Xlistproc.c and serverd.c (where applicable), and you may not redistribute
- Xany changes you may have made. No part of the source code bearing a
- Xcopyright notice can be included in commercial software systems without
- Xwritten permission by the author.
- XBy using this software you are bound by this agreement.
- XThis software comes with no warranties and cannot be sold for profit.
- XThe AGREEMENT and COPYRIGHT notices should be included in all source
- Xfiles when distributing this software.
- XCOPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- XUse, duplication or disclosure by the Federal Government is subject to the
- Xrestrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- Xfor Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X
- XUPDATES: All updates can be obtained from cs-ftp.bu.edu (128.197.13.20) via
- Xanonymous ftp, in the directory pub/listproc. If you downloaded this version
- Xfrom another ftp site, please keep an eye on cs-ftp.bu.edu. Bug fixes will
- Xbe posted periodically over there, and no notifications will be posted to
- Xnews; you should check the directory periodically.
- X
- XCOMPILER: The programs are written to be ANSI C compliant (almost); if your
- Xcompiler cannot handle them, I suggest you also download unproto.tar.Z
- Xfrom cs-ftp.bu.edu; cd pub/unproto; this is a nice set of programs that will
- Xconvert ANSI-isms to old style C -- please send any questions about unproto
- Xto its author, not me. In this case, follow the instructions in the Makefile
- Xin the src directory for adjustments to be able to use this package.
- XFor those compilers that die when they see a contol-L in the source code, I
- Xhave written a C program that "cleans" source files; it is called clean.c and
- Xcan be found in pub/utils as well; compile as follows:
- X % cc -Dunix clean.c -o clean
- XThe compiler should support symbol names longer than 8 characters. Also consult
- Xthe Makefile, as well as the PORT SPECIFIC section in ../doc/server.1
- X
- XLINKING: If you are using the interactive part of ListProcessor and your
- Xsetup uses a name server, you may wish to link with libraries that provide
- XDNS support (for example, on SYSV R4 compile with -lsockdns instead of
- X-lsocket).
- X
- XPREPROCESSOR: Strings are defined using both ANSI C specifications and
- Xnon-ANSI standards, so that unproto will work correctly (unproto 2.0 does not
- Xhandle ANSI string concatenations). Which ones are used during compilation
- Xdepends whether the macro __STDC__ is defined by the compiler/preprocessor.
- XNote: the script 'stds' is now rarely needed and can be obtained from cs-ftp.bu.edu
- Xin the directory pub/listproc/utils.
- X
- XSOURCE CODE MODIFICATIONS: If you modify the code to work around problems
- Xwith your operating system, or enhance the system, please send me diff's
- Xto be incorporated in the next release.
- X
- XTCP/IP SUPPORT: The 'system' mailmethod and the live ListProcessor require
- Xsupport for Berkeley sockets and internet support. The system defines the macro
- XTCP_IP in defs.h. Remove this definition if your host does not support sockets,
- Xetc. Failure to do so will lead to compiler errors.
- X
- XSEMAPHORE/SIGNAL SUPPORT: The interactive part of the system depends on
- Xsemaphore support. If your host does not support semaphores, undefine the
- Xsymbol GO_INTERACTIVE in defs.h; this symbol is automatically undefined if
- XTCP_IP is not defined, or the SIGCLD/SIGCHLD, SIGUSR1 and SIGUSR2 signals are
- Xnot present. The system uses the POSIX waitpid() function which may not be
- Xavailable on your system (like Sequent for example). You may use wait3()
- Xinstead; see serverd.c, sighandle(). If you use wait3() and its first argument
- Xwhould be a union, then compile with -DWAIT3_NEEDS_UNION (integer is used by
- Xdefault).
- X
- XSPECIAL HEADER FILES: Platforms that have the <sys/select.h>, <ulimit.h>
- Xand/or <setjmp.h> header files should use -DHAVE_SELECT_H -DHAVE_ULIMIT_H
- Xand -DHAVE_SETJMP_H when compiling.
- X
- XSIGNALS: Various UNIX versions deal with signals in a number of ways.
- XIf your UNIX is strict SYSVR4 compile with -Dsvr4 -- SYSVR4 uses sighold() and
- Xsigrelse(); if it is SYSVR3 compile with -Dsvr3 -- the same functions are
- Xdefined; if it is strict BSD based compile with -Dbsd -- BSD uses
- Xsigblock() and sigsetmask(). If your system does not define either of these
- Xsets of routines or is not a strict implementation of the above, do not
- Xuse the above flags and certain signals will be ignored at certain times
- Xdue to an old- bug with system(). In defs.h certain ports are given
- Xpredefined flavors.
- X
- XNON-BLOCKING I/O: The system employs a timeout mechanism that works
- Xonly with the 'system' mailmethod, provided that the host supports
- Xnon-blocking I/O; if it does not, undefine the symbol NONBLOCKING_IO
- Xin defs.h (defined by default).
- X
- XLOCKS: The system relies heavily on locks; however, a number of systems
- Xdo not support locking across NFS mounted file systems, or do not support
- Xlocks at all. If you are experiencing locking problems, define the symbol
- XNO_LOCKS in defs.h (or compile with -DNO_LOCKS) and pray, or move the system
- Xto a local file system. The following ports have NO_LOCKS automatically
- Xdefined: Minix, Ultrix, NeXT, Apollo, Xenix, Convex.
- X
- XSYSLOG: You may use syslog(3) for reporting if you compile with
- X-DSYSLOG=facility.
- X
- XUSING ANOTHER HOST TO SEND MAIL: By default, the 'system' mailmethod connects
- Xto "localhost" for mail delivery; you may use another host by altering the
- Xsymbol SENDMAIL_HOST in sysmail.h
- X
- XSUBSCRIPTION SUSPENSION: The system scans error messages looking for addresses
- Xto suspend sending mail to, and it allows by default a 7 day grace period. This
- Xperiod may be changed by altering list.h or by compiling with
- X-DGRACE_PERIOD=time_in_seconds.
- X
- XErrors-To: lines: If you do not want the system to put Errors-To: lines
- Xcompile with -DNO_ERRORS_TO.
- X
- XZMAILER and other non-sendmail mailers: If your mailer requires a
- X'HELO hostname' or 'HELO ip-address' greeting, then compile with -DZMAILER.
- XIf TCP/IP is available, the host's name and IP address are obtained with system
- Xcalls. If not, they default to "localhost" and "127.0.0.1" (see defs.h) and
- Xthey have to redefined. By default, the hostname is included in the greeting.
- XIf the IP address is required, see list.c and listproc.c.
- X
- XUPGRADING: If you are upgrading from an earlier version, take a look at the
- XUPGRADING and PORT SPECIFIC sections in ../doc/server.nr and run the
- Xupgrade_to_6.0c shell script.
- X
- XPORTS: The code has been ported to the following UNIXes:
- XSUN, IBM, SGI, DEC, HP, Convex, Stardent, KPC, NeXT, SCO, Apollo, Sequent, Data
- XGeneral, i860, i386 (bsd) and OSF. If you are on a different host, try first
- Xcompiling with -Dunknown_port.
- X
- XINSTALLATION DIRECTORY: Change the HOMEDIR symbol in Makefile to be the top
- Xlevel directory where this system is installed.
- X
- XFORUM: You should join our forum at unix-listproc@avs.com where we
- Xdiscuss problems and enhancements about this system; send a subscribe request
- Xto listproc@avs.com
- X
- XACKNOWLEDGEMENTS: I would like to thank the following people for their
- Xsuggestions and contributions to this system (not all suggestions have been
- Xincorporated):
- X1) Bob Boyd (rbn@epavax.rtpnc.epa.gov): IRIX port, gateway connections
- X feedback, 5.3 beta testing. [Since Dec. 1992 Bob is no longer at EPA
- X and I wish him good luck]
- X2) Stefan Schroer (Stefan.Schroer@cyber.urz.uni-wuppertal.dbp.de): MINIX port
- X (code not reported since 5.0), help files, original 'get' and 'index'
- X requests.
- X3) Scott J. Ellentuch (tuc@stormking.com): IBM R6000 port, enhancements to
- X the farch utility, 5.3&up beta testing, setting up of the unix-listproc
- X forum, endless support on the net -- he is my buddy.
- X4) David Warner (warner@austin.onu.edu): IBM R6000 bug fixing, 5.3 beta
- X testing, tolerance with my obnoxious code -- I owe this gentleman a lot.
- X5) Nathan F. Estey (nestey@copper.Denver.Colorado.EDU): 5.4 suggestions.
- X6) Aad Nienhuis (aad@sconar.sco.uva.nl) for the catmail utility.
- X7) Warren Burstein (warren@itexjct.jct.ac.il): digests, owner moderated lists
- X (listproc sends messages to owner, owner sends back the approved ones --
- X my scheme uses APPROVE and DISCARD requests), significant code rewriting,
- X manager preferences, automatic archiving of messages.
- X8) Nicos Kontopoulos (nicos@cs.bu.edu) for a lot of tiny suggestions.
- X9) Matthias Klose <doko@cs.tu-berlin.de>, John Neil <neil@dehn.mth.pdx.edu>
- X for the NeXT port.
- X10) Ken Mayer (ken@visix.com) for the Precedence: stuff.
- X11) Henry Spencer for the pattern matching routines.
- X12) Carlos O'Ryan Lira (coryan@mat.puc.cl) for the Apollo port.
- X13) Anand V Raman (A.Raman@massey.ac.nz) for modifying 'setup' to rebuild the
- X system under the HOMEDIR definition in Makefile.
- X14) Kenneth Lorber (keni@oasys.dt.navy.mil) for providing fio.c and speeding up
- X the system by reducing the number of syscom()'s.
- X15) All of those of you who made literally a myriad of small suggestions here
- X and there, and contributed even a single character of code, and especially
- X all of you who let me into your systems to do the ports myself.
- X
- X The ListProcessor system includes 158 files:
- X
- X HOMEDIR/doc:
- X *.nr -- proformatted man pages
- X catmail.1 -- man page for the catmail utility
- X farch.1 -- man page for the file archiving utility
- X ilp.1 -- man page for the Interactive ListProcessor client
- X list.1 -- man page for the mailing list processing application
- X listproc.1 -- man page for the request processing application
- X queue.1 -- man page for the mail queue processing application
- X server.1 -- man page describing the system
- X serverd.1 -- man page for the system daemon
- X start.1 -- man page for the system's housekeeper
- X README -- instructions for installing the man pages on your system
- X
- X HOMEDIR/help:
- X TOPICS -- index file with topics and corresponding filenames
- X general -- general help file
- X approve -- help on the approve request
- X discard -- help on the discard request
- X information -- help on the information request
- X lists -- help on the lists request
- X recipients -- help on the recipients request
- X set -- help on the set request
- X statistics -- help on the statistics request
- X subscribe -- help on the subscribe request
- X unsubscribe -- help on the unsubscribe request
- X index -- help on the index request
- X get -- help on the get request
- X release -- help on the release request
- X which -- help on the which request
- X reports -- help on the reports request
- X edit -- help on the edit request
- X put -- help on the put request
- X live -- help on how to access the live ListProcessor
- X listproc -- help on this system
- X fax -- help on the fax request
- X search -- help on the search request
- X run -- help on the run request
- X
- X HOMEDIR/archives:
- X HOMEDIR/archives/listproc: Master archive:
- X DIR -- info on files and directories they are located
- X INDEX -- master index of all archives (listproc, pub, unix)
- X summary-of-requests -- list of all commands
- X info -- info on this archive
- X HOMEDIR/archives/listproc/example.dat:
- X example.dat1 -- part 1 of file example.dat in archive listproc
- X example.dat2 -- part 2 of file example.dat in archive listproc
- X example.dat3 -- part 3 of file example.dat in archive listproc
- X HOMEDIR/archives/ilp: Source files for the ILP client:
- X DIR -- info on files in this subdirectory
- X INDEX -- index of all archives in this archive
- X ilp.c -- the ILP client
- X ilp.h -- specific definitions for ilp.h
- X ilpp.h -- definition of ILP Protocol
- X ilp.1 -- (as before)
- X ilp.nr -- (as before)
- X makefile -- makefile to build the ILP client
- X HOMEDIR/archives/pub: Subarchive of listproc:
- X DIR -- info on files and directories they are located
- X INDEX -- index of all archives in this archive
- X info -- info on this archive
- X HOMEDIR/archives/unix: Subarchive of listproc:
- X DIR -- info on files and directories they are located
- X INDEX -- index of all archives in this archive
- X info -- info on this archive
- X HOMEDIR/archives/pub/unix: Subarchive of pub (duplicate name example):
- X DIR -- info on files and directories they are located
- X INDEX -- index of files in this archive
- X info -- info on this archive
- X HOMEDIR/archives/pub/private: Subarchive of pub; example private archive
- X DIR -- info on files and directories they are located
- X INDEX -- index of files in this archive
- X info -- info on this archive
- X
- X HOMEDIR/src:
- X REGISTRATION -- registration form for using this software
- X README -- this file
- X global.h -- global variables definitions
- X struct.h -- defines the server structure
- X defs.h -- general definitions
- X tlock.c -- tests for locks, i.e. whether any server programs are running
- X on another file system via NFS
- X list.h -- specific definitions for list.c
- X list.c -- the list's server
- X listproc.h -- specific definitions for listproc.c
- X listproc.c -- server for individual requests
- X pqueue.h -- specific definitions for pqueue.c
- X pqueue.c -- processes the mail queue
- X serverd.h -- specific definitions for serverd.c
- X serverd.c -- parent program that spawns list or listproc
- X start.h -- specific definitions for start.c
- X start.c -- does housekeeping before spawning serverd, makes sure that
- X files exist, kills any running server processes, etc
- X sysmail.h -- specific definitions for sysmail.c
- X sysmail.c -- system mailmethod routines
- X catmail.h -- specific definitions for catmail.c
- X catmail.c -- append incoming mail to the appropriate file
- X signals.c -- signal processing routines
- X sender.c -- sender address manipulation routines
- X misc.c -- general purpose routines
- X farch.c -- utility for easy archiving of files
- X next.h -- specific definitions for NeXT hosts
- X sem.c -- semaphore definitions for serverd's interactive part
- X rev.c -- source to BSD 'rev'
- X ilpp.h -- Interactive ListProcessor Protocol definition
- X ilp.h -- specific definitions for ilp.c
- X ilp.c -- client application to connect to an interactive system
- X silp.c -- system ilp used by ListProcessor to connect to remote servers
- X regex.c -- fornt end to pattern matching routines
- X regerror.c -- pattern matching routines -- Henry Spencer
- X regexp.c -- pattern matching routines -- Henry Spencer
- X regexp.h -- pattern matching routines -- Henry Spencer
- X regmagic.h -- pattern matching routines -- Henry Spencer
- X regsub.c -- pattern matching routines -- Henry Spencer
- X fwin.c -- utility that returns subsets of files
- X fio.c -- simple system calls submitted by keni@oasys.dt.navy.mil
- X strftime.c -- UC Berkeley public domain version of this function
- X semset.c -- utility to check/set a semaphore's value
- X Makefile -- to build your own server
- X
- X HOMEDIR/src/ansi:
- X *.h -- specific ANSI string definitions for various programs
- X
- X HOMEDIR/src/nonansi:
- X *.h -- specific non-ANSI string definitions for various programs
- X
- X HOMEDIR/gateway:
- X gateway.c -- gateway for connecting your host to another on Internet
- X gateway.h -- specific definitions for gateway.c
- X ilpp.h -- definition of the interactive ListProcessor Protocol
- X README -- how to install and use the gateway
- X Makefile -- how to build the gateway
- X
- X HOMEDIR/util:
- X combine.c -- user utility to automatically combine archive files
- X received in multiple mail messages
- X expn.c -- check if address is reachable
- X check_addr -- script to check the validity of an incoming address
- X mmdfcatmail.c -- utility to use before catmail if using an MMDF mailer
- X which.sh -- UCB "which" source
- X use_From:_address.sh -- program+script to use the From: address instead of
- X the "From " for identification
- X
- X HOMEDIR:
- X makefile -- to build your system
- X ILPP -- description of the ILP protocol
- X setup -- a script to be run before starting for the first time
- X systest -- script that analyzes your system
- X queued -- daemon controlling the processing of the mail queue
- X peer -- script to add a peer list
- X news -- script to add a news group to a list
- X redux -- script that reduces the size of mbox by removing unnecessary
- X fields from the header of each message
- X ulock -- in conjunction with the 'flocks' file, this utility
- X removes all locked files (unlocks them)
- X flocks -- script to remove locked files
- X .awk -- awk program used for the 'statistics' and 'recipients'
- X ListProcessor requests
- X .stats -- shell script used for the 'statistics' ListProcessor request
- X .grep -- shell program used for the 'statistics' ListProcessor request
- X .ignored -- a list of email addresses whose messages are ignored
- X owners -- a list of all list owner addresses
- X unwanted.hosts -- hosts not allowed to connect to ILP
- X upgrade_to_6.0c -- upgrade script
- X welcome.live -- welcome message upon live log in
- X README -- general guidelines for first time users
- X FAQ -- most frequently asked questions
- X WHATS_NEW -- what's with this version
- X config -- the system's configuration file
- X
- X
- X |-->-----------> START
- X | |
- X | |
- X ^ (spawns-and-dies)
- X | |
- X | |
- X |--<--restart--- SERVERD <--shutdown-<--|
- X /\ r
- X / \ e
- X / \ s
- X (spawns either one as necessary) t
- X / \ a
- X / \ r
- X LIST LISTPROC --->---t
- X
- X
- XThe diagram shows that 'start' spawns 'serverd' and then dies, and that
- X'listproc' may request 'serverd' to die (shutdown) or request that the
- Xsystem is restarted, in which case 'serverd' spawns 'start' and dies.
- X
- XEnjoy!
- X
- XRevision history:
- X
- XVersion Date Status Comments
- X------------------------------------------------------------------------------
- X 3.45 12/20/90 Outdated * First public version; bugs with listproc
- X 3.67 01/03/91 Outdated Bugs fixed
- X 3.68 01/04/91 Outdated * v3.67 + tlock utility
- X 4.0 04/09/91 Exprmntl v3.68 + STATISTICS listproc command
- X 4.1 04/16/91 Outdated v4.0 + redux utility
- X 4.2 05/02/91 Outdated v4.1 w/ optimized source code, better doc.
- X 4.21 05/03/91 Outdated v4.2 w/ redux which was left out by mistake
- X 4.3 05/03/91 Outdated * v4.21 w/ better mailer-daemon msg handling
- X 4.4 05/22/91 Exprmntl v4.3 w/ enhanced tlock,control,start,listproc
- X 4.5 06/12/91 Exprmntl v4.3 w/ enhanced listproc
- X 5.0 07/17/91 Outdated * v4.4 + support for multiple lists
- X 5.1 08/27/91 Outdated v5.0 + bug fixes, enhanced listproc
- X 5.1 Rev I 10/03/91 Outdated v5.0 + more bug fixes
- X 5.2 10/08/91 Outdated * v5.1 + archives, GET, INDEX requests,
- X farch utility, moderated lists,
- X disabled listproc commands on a per list
- X basis, link with peer lists and news
- X feeds
- X 5.2 Rev A 10/10/91 Outdated v5.2 + bug fixes
- X 5.21 10/15/91 Exprmntl v5.2A + multiple recipients in one message
- X 5.3 beta 10/31/91 Exprmntl v5.21 + system mailmethod, bug fixes
- X 5.3 12/05/91 Outdated v5.21 + bug fixes, universal system mailmethod,
- X multiple recipients in one message,
- X support for blanks in email addresses,
- X user-set limit on size of messages,
- X RFC 821 compliant SMTP implementation,
- X extensive mail loop detection mechanism,
- X new scripts (stds, reformat), enhanced
- X GET request, and more.
- X 5.31 12/09/91 PstdNews * v5.3 + mail queueing capability/subsystem +
- X RELEASE request
- X 5.4 beta 12/16/91 Exprmntl v5.31 + crash recovery mechanism, manager
- X approved subscriptions (private lists),
- X multiple lines of text for describing
- X archived files, batch processing,
- X WHICH request, automatic use of
- X unproto in the Makefile, private
- X archives, list owners with restricted
- X system privileges, email aliasing
- X for requests, SYSTEM/REPORTS/PUT/EDIT
- X list administration requests, automatic
- X archiving of distributed messages only,
- X enhanced INDEX/GET requests, same
- X archive names allowed on different
- X levels of the hierarchy (path spec. to
- X an archive)
- X 5.4 02/05/92 Outdated v5.31 + v5.4 beta
- X 5.41 03/05/92 PstdNews * v5.4 + catmail (system is now more secure), bug
- X fixes, owner preferences
- X 5.5 beta 04/08/92 Exprmntl v5.41 + two ways for moderating lists by owners
- X (+ APPROVE/DISCARD list administration
- X requests), enhanced farch, fix to GET
- X request, list digests, optional
- X Comment: line, manager preferences,
- X enhanced help system, GET/INDEX
- X requests now report file sizes, new
- X config options ignore_invalid_requests
- X and relaxed_syntax, EXECUTE request
- X 5.5 05/18/92 Outdated v5.5 beta + NeXT port
- X 6.0beta 01/19/93 Exprmntl v5.5 + interactive system, ULISTPROCESSOR_UMASK
- X env var, Precedence:, configurable
- X headers, regular expressions, auto
- X archiving of lists' messages, enhanced
- X farch, ability to execute commands
- X on a per list basis, ability to
- X continue commands in the config file on
- X multiple lines, HP, Apollo, Sequent &
- X DG ports, interception of requests sent
- X to a list, list defaults, CONCEAL
- X attribute, user settable subscription
- X addresses, various user utilities,
- X gateway client, screening and analysis
- X of error messages, support for syslog,
- X auto splitting of outgoing files, FAX
- X request
- X
- X 6.0 04/01/93 Outdated v6.0beta + ports + bug fixes + SEARCH request
- X 6.0a 07/20/93 Outdated v6.0 + VIEW requests server/client abort
- X operation, more bug fixes, true
- X concurrency
- X 6.0b 09/13/93 Outdated * v6.0a + tons of bug fixes, better mail loop
- X detection
- X 6.0c 11/30/93 Released v6.0b + ability not to compress archived files,
- X ULISTPROC_ARCHIVES_UMASK env var, bug
- X fixes
- X
- X*Source for these versions has been posted to news.
- *-*-END-of-src/README-*-*
- echo x - src/REGISTRATION
- sed 's/^X//' >src/REGISTRATION <<'*-*-END-of-src/REGISTRATION-*-*'
- X
- X LISTPROCESSOR SYSTEM
- X --------------------
- X
- X Copy Registration
- X
- X tasos@cs.bu.edu
- X
- XKeep an eye on the anonymous ftp site cs-ftp.bu.edu (128.197.13.20) in the directory
- Xpub for any updates.
- X
- XThe list unix-listproc@avs.com served by listproc@avs.com
- Xis a forum about this system.
- X
- XIf you use this software and have not filled out a registration form before,
- Xplease email me the following information:
- X
- XName:
- XEmail address:
- XOrganization:
- XAddress:
- XPhone:
- XType of computer system:
- XVersion of server using (% list -v):
- XComments:
- *-*-END-of-src/REGISTRATION-*-*
- echo x - src/Makefile
- sed 's/^X//' >src/Makefile <<'*-*-END-of-src/Makefile-*-*'
- X# Makefile for ListProcessor 6.0
- X#
- X# The programs are written to be fully ANSI C compliant. The symbol CC below
- X# may have to be redefined if an ANSI C compiler is to be used. This ANSI
- X# compiler should define the marco __STDC__
- X#
- X# Suggestions:
- X# SGI: IRIX 4: cc -ansi -D_POSIX_SOURCE, or cc -D__STDC__ -D_POSIX_SOURCE
- X# SGI: IRIX 5: cc -D_BSD_SOURCE -Dsvr4
- X# SUN SUNOS 4.x: Use /usr/lang/acc when available; compile with
- X# -DSETPGRP_NEEDS_ARGS
- X# SUN Solaris 5.2+: Compile with -Dsvr4; link with -lsocket -lnsl
- X# NeXT: Compile with -D__NeXT__ if the compiler does not define this symbol,
- X# and -I/usr/include/bsd -I/usr/include/bsd/sys; also with
- X# -DSETPGRP_NEEDS_ARGS
- X# HP-UX: cc -Aa -D_HPUX_SOURCE
- X# IBM: xlc -D_ALL_SOURCE -qnoro -DSETPGRP_NEEDS_ARGS
- X# SYSVR4 Systems: link with -lnsl and -lsocket or -lsockdns if you are using
- X# a name server
- X# SCO: Compile with -Dsco -I/usr/include/netinet
- X# Apollo: Do not compile with -A ansi; if you need to, also compile with
- X# -Dapollo
- X# Sequent: gcc -fwritable-strings
- X# Data General: gcc -fwritable-strings
- X# Stardent/KPC Titan: cc (do not use -43)
- X# OSF: cc -std1 -DSETPGRP_NEEDS_ARGS
- X# i386: cc -fwritable-strings
- X# i860: cc
- X# NetBSD: cc -DNetBSD
- X#
- X# To use the unproto package during compilation, uncomment the symbols
- X# SRC and COMP below, and comment out the default ones.
- X#
- X# Also read the README file in this directory as well as ../doc/server.nr
- X# (the PORT SPECIFIC section)
- X#
- X# On some systems that do not use BSD-style sockets and signals (SIGIO)
- X# you need to link with a BSD library that defines them, although this is not
- X# critical. See the man page for ilp(1) for more details.
- X#
- X# Examples:
- X# AIX: Link with -lbsd
- X# SCO: Link with -lsocket
- X#
- X# SIGNALS: Various UNIX versions deal with signals in a number of ways.
- X# If your UNIX is strict SYSVR4 compile with -Dsvr4 -- SYSVR4 uses sighold()
- X# and sigrelse(); if it is SYSVR3 compile with -Dsvr3 -- the same functions are
- X# defined; if it is strict BSD based compile with -Dbsd -- BSD uses
- X# sigblock() and sigsetmask(). If your system does not define either of these
- X# sets of routines or is not a strict implementation of the above, do not
- X# use the above flags and certain signals will be ignored at certain times.
- X# In defs.h certain ports are given predefined flavors.
- X#
- X# LINKING: If you are using the interactive part of ListProcessor and your
- X# setup uses a name server, you may wish to link with libraries that provide
- X# DNS support.
- X#
- X# Optional compiler flags that can be used:
- X# -DHAVE_SELECT_H: if your system provides the <sys/select.h> include file
- X# -DHAVE_ULIMIT_H: if your system provides the <ulimit.h> include file
- X# -DHAVE_SETJMP_H: if your system provides the <setjmp.h> include file
- X# -DHAVE_TZFILE_H: if your system provides the <tzfile.h> include file
- X# -DSYSLOG=facility: if you want to use syslog(3) for reports
- X# -DNO_LOCKS: if you do not want file locking
- X# -DNO_ABORT_OP: if you do not want abort capability (^C) with live
- X# connections (suggested if compiler errors)
- X# -DNO_TCP_IP: if TCP/IP is not installed or available
- X# -DNO_ERRORS_TO: if you do not want Errors-To: lines in messages
- X# -DDONT_GO_INTERACTIVE: if the system should not go live (see below)
- X# -DERROR_MAIL_ANALYSIS=level: if you want the system to analyze
- X# mailer-daemon error messages and take automatic action; default is
- X# off; level ranges from 1 (very conservative) to 9 (complete analysis +
- X# guess-attempts); see also GRACE_PERIOD below -- this option is still
- X# under development
- X# -DZMAILER: if you are using Zmailer or any other non-sendmail mailer that
- X# requires 'HELO hostname' to start the SMTP transaction; see also below
- X# -DLIST_CHECKING_FOR_REQUESTS: if you want to screen out requests sent to
- X# lists but allow ones that do not refer to local or remote lists
- X# -DLIST_ALIAS_IN_SUBJECT: if you want each subject line to contain the
- X# list's alias and the current message number
- X# -DNEED_DATE: if you need a Date: header line and your sendmail does not
- X# put one
- X# -DWAIT3_NEEDS_UNION: if using wait3() and its first argument is a union
- X# -DSETPGRP_NEEDS_ARGS: if your setpgrp(2) takes arguments
- X# -DNEED_VSPRINTF: if your system does not provide vsprintf()
- X# -DMAX_LISTS=lists+1: number of lists defined plus one; default is 11
- X# -DUCB_MAIL=\"path\": path to UCB mail program; default is /usr/ucb/mail
- X# -DMAX_LINE=size: internal character buffer length; default is 1024
- X# -DMAX_CONNECTIONS=xxx: define the maximum number of live connections over
- X# TCP/IP; default is 5
- X# -DMAX_EMAILS=num: define the number of messages to send before sleeping
- X# to give time to sendmail to catch up; default is 10
- X# -DSHELL_CHAR_LIMIT=limit: define the maximum number of characters the
- X# shell will accept in the command line; default is 2048; used only
- X# with other-than-system mailmethods
- X# -DUSE_CARRIAGE_RETURN_LINEFEED: if using the system mailmethod and your
- X# SMTP protocol requires each line to be terminated by \r\n; default is
- X# \n
- X# -DBUFFSIZ=size: define the socket buffer size for live connections; default
- X# is 8192
- X# -DILP_PORT=port: define another port for live connections if you do not
- X# have access to /etc/services
- X# -DINEWS=\"path\": path to the inews program for posting articles to news
- X# groups; default is /usr/lib/news/inews
- X# -Dbsd: if your host has a BSD flavor; default is defined in defs.h
- X# -Dsvr3: if your host has a SYSV R3 flavor; default is defined in defs.h
- X# -Dsvr4: if your host has a SYSV R4 flavor; default is defined in defs.h
- X# -Dunknown_port: if the system has not been ported to your host; should
- X# use one of the above system types (bsd, svr3, svr4)
- X# -fwritable-strings: specific to gcc; must be used with gcc
- X#
- X# Symbols automatically defined for various hosts (depending on the host):
- X# TCP_IP: defined if NO_TCP_IP is undefined
- X# GO_INTERACTIVE: defined if TCP_IP and SIGCLD (SIGCHLD), SIGUSR1 and SIGUSR2
- X# are defined, and DONT_GO_INTERACTIVE is not requested; requires host
- X# support for either waitpid() or wait3(), and semaphores
- X# NO_LOCKS: defined when a system exhibits locking problems over NFS
- X# NONBLOCKING_IO: undefine it if your host does not support it
- X#
- X# Other symbols that may need tweaking:
- X# HOSTNAME: if TCP_IP is not defined then you need to set your hostname in
- X# defs.h only if you are compiling with -DZMAILER; default is "localhost"
- X# LOCAL_ADDR: same as above; default is 127.0.0.1
- X# SENDMAIL_HOST: default is "localhost"; it defines the host to connect to
- X# when using the 'system' mailmethod to deliver mail (defined in
- X# sysmail.h); compile as follows: -DSENDMAIL_HOST=\"hostname\".
- X# MAILER_DAEMON: email addresses that are given special treatment (defined
- X# in defs.h)
- X# SUSP_SUBJECT: suspicious Subject: lines that get special treatment (defined
- X# in defs.h)
- X# GRACE_PERIOD: time period before subscriptions of erroneous addresses are
- X# suspended; to be used as follows: -DGRACE_PERIOD=time_in_seconds.
- X#
- X# Always run 'setup' (in the parent directory); do not type 'make' in this
- X# directory.
- X
- X# define your compiler:
- XCC = cc
- X
- X# define special symbols (system, preprocessor options, etc):
- XDEFINES = -DHAVE_SELECT_H -DHAVE_ULIMIT_H -DHAVE_SETJMP_H \
- X -DHAVE_TZFILE_H -DERROR_MAIL_ANALYSIS=9 \
- X -DUCB_MAIL=\"/bin/mailx\" \
- X -DUSE_CARRIAGE_RETURN_LINEFEED
- X
- X# define the optimization level
- XOPTIMIZATION = -g
- X
- X# define where the preprocessor is if using unproto:
- X#CPP = /lib/cpp
- X
- X# unproto specific definitions -- use either COMP symbol (second is preferred):
- X#SRC = /tmp/$<
- X#COMP = cat $< | unproto > $(SRC); $(CC)
- X#COMP = $(CPP) $(DEFINES) $< | unproto > $(SRC); $(CC)
- X
- X# default definitions (comment out if using unproto):
- XSRC = $<
- XCOMP = $(CC)
- X
- X# Reset HOMEDIR to the top level directory the system is installed under:
- XHOMEDIR = /usr/server
- X
- X# define linking options and libraries
- XLDFLAGS = $(OPTIMIZATION)
- XLIBS =
- X
- X# Nothing to change below
- XSHELL = /bin/sh
- XLD = $(CC)
- XCFLAGS = -c $(OPTIMIZATION) -I$(PWD) -I$(PWD)/src -I/usr/server/src \
- X -I$(HOMEDIR)/src $(DEFINES)
- XCLEAN_TMP = @if [ $$USE_UNPROTO ]; then \
- X if [ `dirname $(SRC)` = "/tmp" ]; then \
- X rm -f $(SRC); \
- X fi; \
- X else \
- X echo > /dev/null; \
- X fi
- X
- XARCHIVED = signals.o sender.o misc.o sysmail.o sem.o silp.o regex.o \
- X regsub.o regerror.o regexp.o fio.o strftime.o
- XARCHIVE_LIB = libserver.a
- XTARGETS = listproc list serverd start tlock farch pqueue catmail ilp \
- X rev fwin semset
- X
- Xall: $(ARCHIVE_LIB) $(TARGETS)
- X
- X$(ARCHIVE_LIB): $(ARCHIVED)
- X @rm -f $(ARCHIVE_LIB)
- X ar cr $(ARCHIVE_LIB) $(ARCHIVED)
- X @if [ -f /usr/bin/ranlib -o -f /bin/ranlib ]; then \
- X echo ranlib $(ARCHIVE_LIB); \
- X ranlib $(ARCHIVE_LIB);\
- X else\
- X echo ar ts $(ARCHIVE_LIB); \
- X ar ts $(ARCHIVE_LIB); \
- X fi
- X
- Xlistproc: listproc.o $(ARCHIVE_LIB)
- X $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS) -lm
- X
- Xlist: list.o $(ARCHIVE_LIB)
- X $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS) -lm
- X
- Xserverd: serverd.o $(ARCHIVE_LIB)
- X @rm -f $@
- X $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS) -lm
- X
- Xstart: start.o $(ARCHIVE_LIB)
- X $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS)
- X
- Xtlock: tlock.o $(ARCHIVE_LIB)
- X $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS)
- X
- Xfarch: farch.o $(ARCHIVE_LIB)
- X $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS) -lm
- X
- Xpqueue: pqueue.o $(ARCHIVE_LIB)
- X $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS)
- X
- Xcatmail: catmail.o $(ARCHIVE_LIB)
- X $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS)
- X @chmod a+rx $@
- X @chmod u+s $@
- X
- Xilp: ilp.o
- X $(LD) $(LDFLAGS) $@.o -o $@ $(LIBS) -lm
- X @chmod a+rx $@
- X
- Xrev: rev.o
- X $(LD) $(LDFLAGS) $@.o -o $@
- X
- Xfwin: fwin.o
- X $(LD) $(LDFLAGS) $@.o -o $@ $(LIBS) -lm
- X
- Xsemset: semset.o
- X $(LD) $(LDFLAGS) $@.o -o $@ -lm
- X
- Xinstall: $(ARCHIVE_LIB) $(TARGETS)
- X @for t in $(TARGETS); do \
- X echo Installing "$$t"; \
- X rm -f $(HOMEDIR)/"$$t"; \
- X if [ -r /bin/ln -o -r /usr/bin/ln -o -r /usr/ucb/ln -o \
- X -r /usr/bsd/ln ]; then \
- X ln -s $(HOMEDIR)/src/"$$t" $(HOMEDIR)/"$$t"; \
- X else \
- X cp "$$t" $(HOMEDIR); \
- X fi; \
- X if [ "`ls -l $$t | awk '{ print $$3 }'`" = "server" ]; then \
- X chmod a+rx $(HOMEDIR)/"$$t"; \
- X fi; \
- X done
- X @(cd $(HOMEDIR); chmod u+s catmail)
- X
- Xclean:
- X rm -f $(TARGETS) $(ARCHIVE_LIB) *.o
- X
- X# Hand-generated dependencies
- Xlistproc.o: listproc.c defs.h struct.h global.h listproc.h ansi/listproc.h \
- X nonansi/listproc.h ansi/misc.h nonansi/misc.h ansi/defs.h \
- X nonansi/defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xlist.o: list.c defs.h struct.h global.h list.h ansi/defs.h \
- X nonansi/defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xserverd.o: serverd.c defs.h struct.h global.h serverd.h ansi/serverd.h \
- X nonansi/serverd.h ilpp.h ansi/defs.h \
- X nonansi/defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xstart.o: start.c defs.h struct.h global.h start.h ansi/start.h \
- X nonansi/start.h ansi/misc.h nonansi/misc.h ansi/defs.h \
- X nonansi/defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xsender.o: sender.c defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xsignals.o: signals.c defs.h struct.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xsysmail.o: sysmail.c defs.h struct.h sysmail.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xmisc.o: misc.c defs.h struct.h ansi/misc.h nonansi/misc.h ansi/defs.h \
- X nonansi/defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xtlock.o: tlock.c defs.h global.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xfarch.o: farch.c defs.h struct.h listproc.h ansi/defs.h nonansi/defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xpqueue.o: pqueue.c defs.h struct.h global.h pqueue.h ansi/defs.h \
- X nonansi/defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xcatmail.o: catmail.c defs.h struct.h global.h catmail.h ansi/catmail.h\
- X nonansi/catmail.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xsem.o: sem.c defs.h ansi/defs.h nonansi/defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xilp.o: ilp.c ilp.h ilpp.h defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xsilp.o: silp.c ilp.h ilpp.h defs.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xregex.o: regex.c regexp.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xregsub.o: regsub.c regexp.h regmagic.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xregexp.o: regexp.c regexp.h regmagic.h
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xregerror.o: regerror.c
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xrev.o: rev.c
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xfwin.o: fwin.c
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xfio.o: fio.c
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xstrftime.o: strftime.c
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- Xsemset.o: semset.c
- X @PWD=`pwd`
- X $(COMP) $(CFLAGS) $(SRC)
- X @$(CLEAN_TMP)
- X
- *-*-END-of-src/Makefile-*-*
- echo x - src/catmail.h
- sed 's/^X//' >src/catmail.h <<'*-*-END-of-src/catmail.h-*-*'
- X/*
- X Below are the #define's pertinent to catmail.c (user contributed application).
- X*/
- X
- X#ifdef __STDC__
- X# include "ansi/catmail.h"
- X#else
- X# include "nonansi/catmail.h"
- X#endif
- X#ifdef __NeXT__
- X# include "next.h"
- X#endif
- X
- X#define LOST_MAIL "lost+found"
- X
- Xint lfd = 2, lfd2 = 2, lfd3 = 2; /* Set to stderr in case they are closed */
- X /* without having been opened before */
- Xint listid;
- XBOOLEAN tty_echo = TRUE;
- XBOOLEAN moderated = FALSE; /* -m flag off */
- XBOOLEAN reformat = FALSE; /* -f flag off */
- XBOOLEAN requests = FALSE; /* -r flag off */
- XFILE *report = NULL;
- Xint sid = -1;
- *-*-END-of-src/catmail.h-*-*
- echo x - src/defs.h
- sed 's/^X//' >src/defs.h <<'*-*-END-of-src/defs.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X
- X General system definitions.
- X
- X WARNING: DO NOT CHANGE THE NAME OF THE 'SERVERD', 'LIST' or 'LISTPROC'
- X PROGRAMS in the system. If you do so, make sure that command line
- X options are separated by at least a space from the filename.
- X DO NOT INCLUDE ANY CHARACTERS SUCH AS &, |, <, >. etc.
- X
- X Preserve any quotes and new lines that appear below; change only path names.
- X
- X ALWAYS SPECIFY ABSOLUTE PATHS.
- X
- X*/
- X
- X#ifdef _AUX_SOURCE
- X# include <unistd.h>
- X# include <time.h>
- X#endif
- X
- X#ifdef __STDC__
- X# include "ansi/defs.h"
- X#else
- X# include "nonansi/defs.h"
- X#endif
- X
- X#ifndef NO_TCP_IP
- X# define TCP_IP
- X#endif
- X
- X#if defined (TCP_IP) && (defined (SIGCLD) || defined (SIGCHLD)) && \
- X defined (SIGUSR1) && defined (SIGUSR2)
- X# if !defined (GO_INTERACTIVE) && !defined (DONT_GO_INTERACTIVE)
- X# define GO_INTERACTIVE
- X /* Remove this definition if your host doesn't support semaphores etc. */
- X# endif
- X#endif
- X
- X#define COPYRIGHT \
- X"ListProcessor version 6.0 by Anastasios Kotsikonas, Copyright (c) 1991-93.\n\
- XUse, duplication or disclosure by the U.S. Federal Government is subject to the\n\
- Xrestrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,\n\
- Xfor U.S. Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).\n\n"
- X#define SERVICE "ulistproc"
- X#define COMPLETE_FILE(f) if (!interactive) fprintf (f, ".\nQUIT\n")
- X#define TELNET "telnet `hostname` 25 > /dev/null 2>&1 "
- X#ifndef INEWS
- X# define INEWS "/usr/lib/news/inews"
- X#endif
- X#ifdef xenix
- X# define BINMAIL "/usr/bin/mail > /dev/null 2>&1"
- X#else
- X# define BINMAIL "/bin/mail > /dev/null 2>&1"
- X#endif
- X
- X#define SUBSCRIBERS ".subscribers"
- X#define ALIASES ".aliases"
- X#define NEWSF ".news"
- X#define PEERS ".peers"
- X#define HEADERS ".headers"
- X#define RESTRICTED ".restricted"
- X#define IGNORED ".ignored"
- X#define INFO_FILE ".info"
- X#define WELCOME_FILE ".welcome"
- X#define LIST_LIMITS ".limits"
- X#define UNPROC_MESSAGES ".un.messages"
- X#define UNPROC_SUBSCRIBERS ".un.subscriber"
- X#define UNPROC_PEERS ".un.peers"
- X#define UNPROC_NEWS ".un.news"
- X#define UNPROC_DIGEST ".un.digest" /* digest ready to send */
- X#define DIGEST_TOC ".digest.toc" /* digest table of contents */
- X#define DIGEST_MSG ".digest.msg" /* digest of messages */
- X#define DIGEST_TIME ".digest.time" /* time last digest sent */
- X#define REPORT_LIST ".report.list"
- X#define REPORT_LIST_ACC ".rep.list.acc"
- X#define LIST_MAIL_FILE "mail"
- X#define LIST_MODERATED_F "moderated"
- X
- X#define MESSAGE_IDS_F ".message.ids"
- X
- X#define INDEX "INDEX"
- X#define DIRF "DIR"
- X#define DEFAULT_ARCHIVE "listproc"
- X
- X#define START_OPTIONS "-crs" /* provide start options here */
- X#ifndef apollo
- X# define CUT "cut"
- X#else
- X# define CUT "/sys5.3/usr/bin/cut"
- X#endif
- X#define AWK "awk" /* Do a 'which awk' for proper path */
- X#ifdef _AIX
- X# define UPTIME "ruptime"
- X#else
- X# define UPTIME "uptime" /* 'which uptime'; may use ruptime */
- X#endif
- X#define MAILER_DAEMON "<MAILER&~.+@.+\\.MAILER.+>|SMTP@|\
- X<DA?EMON&~DEMON\\.CO\\.UK>|POST.*MAST|^ROOT| WPUSER|MMDF|^SMT.*|\\$EMD|\
- XMRGATE|VMMAIL|MAIL.*SYSTEM|UUCP|-MAISER-|^MAL@|MAIL.+AGENT|TCPMAIL|BITMAIL|\
- XMAILMAN|MAIL_SYSTEM|^LISTSERV|^LISTPROC|^SERVER"
- X /* Preserve upper case; put all possibilities above
- X separated by a '|'; all of the above entries will
- X be used to identify mailer daemon messages so
- X they can get special treatment; entries are
- X regular expressions */
- X#define SUSP_SUBJECT \
- X"DELIVERY[ \t]+ERROR|\
- XDELIVERY[ \t]+REPORT|\
- XDELIVERY[ \t]+PROBLEM|\
- XWARNING[ \t]+FROM[ \t]+UUCP|\
- XUSER[ \t]+UNKNOWN|\
- XUNDELIVER.+[ \t]MAIL|\
- XUNDELIVER.+[ \t]MESSAGE|\
- XPROBLEMS.+DELIVERING.+MAIL|\
- XPROBLEMS.+DELIVERING.+MESSAGE|\
- XCAN[ \t]*['NO]*T.+DELIVER.+MAIL|\
- XUNABLE.+DELIVER.+MAIL|\
- XUNABLE.+DELIVER.+MESSAGE|\
- XFAILED[ \t]+MAIL|\
- XFAILED[ \t]+MESSAGE|\
- XMAIL[ \t]+FAILED|\
- XMAIL[ \t]+RETURNED|\
- XRETURNED[ \t]+MAIL|\
- XSYSTEM[ \t]+ERROR|\
- XMAIL.*[ \t]ERROR|\
- XMAIL[ \t]+RECEIVED|\
- XMESSAGE[ \t]+RECEIVED|\
- XMESSAGE[ \t]+DELIVER|\
- XMAIL[ \t]+DELIVER|\
- XINTERCEPTED[ \t]+MAIL|\
- XWAITING[ \t]+MAIL|\
- XREAD[ \t]+RECEIPT|\
- XRECEIPT[ \t]+NOTIFICATION|\
- XSTATUS.+SIGNAL[ \t]+[0-9]+|\
- X^ERROR[ \t]+CONDITION[ \t]+RE:|\
- XAUTO[ \t]+REPLY|\
- XAUTOMATIC[ \t]+REPLY|\
- XAUTOMATICALLY[ \t]+GENERATED|\
- XWAITING.+MAIL|\
- XON[ \t]+VACATION|\
- XVIA[ \t]+VACATION|\
- XCONCIERGE[ \t]+NOTICE|\
- XAWAY[ \t]+FROM.+MAIL|\
- XCAN[ \t]*['NO]*T.+ANSWER|\
- XCAN[ \t]*['NO]*T.+REPLY|\
- XOUT[ \t]+OF[ \t]+TOWN|\
- XUNSUBSCRIBE|\
- XREMOVE[ \t]+ME|\
- XADD[ \t]+ME|\
- X^[ \t]*TEST[ \t]*$|\
- X^[ \t]*TEST.+IGNORE|\
- XPLEASE[ \t]+IGNORE"
- X /* List of suspicious subject lines; possible mail
- X loop */
- X#ifndef UCB_MAIL
- X# define UCB_MAIL "/usr/ucb/mail" /* Path to UCB mail program. Redefine
- X it if UCB mail is not installed on your system */
- X#endif
- X
- X/*
- X These #define's should not be altered.
- X*/
- X
- X#ifndef NSIG
- X# ifdef MAXSIG
- X# define NSIG MAXSIG
- X# else
- X# define NSIG 32
- X# endif
- X#endif
- X
- X#define DEFAULT_ILP_PORT 372 /* As assigned by the IANA */
- X#define MAX_COMMANDS 28 /* # of commands recognized */
- X#ifndef MAX_EMAILS
- X#define MAX_EMAILS 10 /* ListProcessor emails in one outgoing batch */
- X#endif
- X#define MAX_FILE_LENGTH 500 /* Number of lines of files when shrunk */
- X#ifndef BUFFSIZ
- X# define BUFFSIZ 8192 /* Socket buffer size */
- X#endif
- X#define DEFAULT_SERVER_ADDRESS "listproc"
- X#define DEFAULT_SERVER_CMDOPTIONS ""
- X#define DEFAULT_SERVER_COMMENT "Boston University ListProcessor"
- X#define DEFAULT_MANAGER "server"
- X#define DEFAULT_PRECEDENCE "bulk"
- X#ifndef MAX_LINE
- X# define MAX_LINE 1024
- X#endif
- X#define EOS '\0'
- X#define RESET(var) (var[0]) = EOS
- X#define BSD_PS 0x01
- X#define SYSV_PS 0x02
- X#define USE_TELNET 0x04
- X#define USE_ENV_VAR 0x08
- X#define USE_MY_SYSTEM 0x10
- X#define BSD_MAIL 0x20
- X#define POST_MAIL 0x40
- X#define GATE_MAIL 0x80
- X#define USE_SYSMAIL 0x100
- X#define LIMIT_MSG 0x200
- X#define LIMIT_FILES 0x400
- X#define IGNR_INVLD_RQSTS 0x4000
- X#define RELAXED_SYNTAX 0x8000
- X#define NON_AUTO_SUB 0x10000
- X#define CONCEAL_LIST 0x20000
- X#define ARCHIVE_LIST 0x40000
- X#define ARCHIVE_DIGEST 0x80000
- X#define START_OF_MESSAGE "From " /* mail messages start w/ this string */
- X#define ACK "ACK" /* Send message back to sender */
- X#define NOACK "NOACK" /* Do not send message back to sender */
- X#define POSTPONE "POSTPONE" /* Postpone sending mail */
- X#define DIGEST "DIGEST" /* send mail in digests */
- X#define MAX_SET_OPTIONS 4
- X
- X#define MAX_OWNER_PREFS 15
- X#define CCSET "CCSET"
- X#define CCSUB "CCSUBSCRIBE" /* Copy owner on subscribe request */
- X#define CCUNSUB "CCUNSUBSCRIBE" /* Copy owner on unsubscribe req */
- X#define CCREC "CCRECIPIENTS"
- X#define CCINFO "CCINFORMATION"
- X#define CCSTAT "CCSTATISTICS"
- X#define CCGET "CCGET"
- X#define CCINDEX "CCINDEX"
- X#define CCLISTS "CCLISTS"
- X#define CCRELEASE "CCRELEASE"
- X#define CCHELP "CCHELP"
- X#define CCPRIVATE "CCPRIVATE"
- X#define CCRUN "CCRUN"
- X#define CCERRORS "CCERRORS" /* Copy owner on errors */
- X#define CCALL "CCALL" /* Copy onwer on all activities */
- X
- X#define ccset 0x01
- X#define ccsub 0x02
- X#define ccunsub 0x04
- X#define ccrec 0x08
- X#define ccinfo 0x10
- X#define ccstat 0x20
- X#define ccget 0x40
- X#define ccindex 0x80
- X#define cclists 0x100
- X#define ccrelease 0x200
- X#define cchelp 0x400
- X#define ccprivate 0x800
- X#define ccrun 0x1000
- X#define ccerrors 0x2000
- X#define ccall ccset | ccsub | ccunsub | ccrec | ccinfo | ccstat |\
- X ccget | ccindex | cclists | ccrelease | cchelp |\
- X ccprivate | ccrun | ccerrors
- X
- X#define MAX_SIGNAL NSIG /* Highest system signal caught */
- X#define BOOLEAN unsigned int
- X#ifndef TRUE
- X# define TRUE 1
- X#endif
- X#ifndef FALSE
- X# define FALSE 0
- X#endif
- X#define CANT_OPEN (-1)
- X#define CANT_LOCK (-2)
- X#define SUBSCRIBED TRUE /* Subscribed sender */
- X#define NOTSUBSCRIBED FALSE /* Sender is not subscribed */
- X#define NEWS TRUE+1 /* News feed */
- X#define PEER TRUE+2 /* Peer messages */
- X#define OWNER TRUE+3 /* Sender is a list owner */
- X#define MANAGER TRUE+4 /* Sender is the manager */
- X#define NEW_ARRIVAL "\n--- NEW MAIL HAS ARRIVED ---\n"
- X#define PROCESSING_BATCH "\n--- PROCESSING BATCH REQUESTS ---\n"
- X#define DIGEST_TIME_ "\n--- DIGEST TIME ---\n"
- X#ifndef MAX_LISTS
- X# define MAX_LISTS 11 /* It should be one more than # desired */
- X#endif
- X
- X#define SEM_REQ_ID 0x01
- X#define SEM_SYSFILES 0x02
- X#define SEM_LISTFILES 0x04
- X#define SEM_ARCHIVES 0x08
- X#define SEM_DLVR_MAIL 0x10
- X
- X#define RECEIVED "^(Received:[ \t])"
- X#define FROM "^(From:[ \t])"
- X#define SUBJECT "^(Subject:[ \t])"
- X#define MESSAGE_ID1 "^(Message-Id:[ \t])"
- X#define MESSAGE_ID2 "^(Message-ID:[ \t])"
- X#define MESSAGE_ID3 "^(Message-id:[ \t])"
- X#define MESSAGE_TAG "^(Message-Tag:[ \t])"
- X#define LISTPROC_ID "^X-Listprocessor-Version:[ \t]|\
- XX-Listserve?r?-Version:[ \t]|^Version:[ \t]"
- X#define ERROR_CONDITION "Error Condition Re: "
- X#define PRECEDENCE "^(Precedence:[ \t])"
- X#define LOW_PRECEDENCES "BULK|JUNK|LOW"
- X
- X#define COMPLETE_TELNET(f) \
- X if (sys.options & USE_TELNET) \
- X COMPLETE_FILE (f)
- X
- X#define OPEN_FILE(fp, file, mode, func) \
- X if ((fp = fopen (file, mode)) == NULL)\
- X report_progress (report, tsprintf ("\n%s(): Could not open %s: errno %d",\
- X func, file, errno), TRUE),\
- X gexit (1)
- X
- X#define COPY_OWNER(mask) (BOOLEAN)\
- X((listid < 0 ? sys.server.manager_prefs : sys.lists[listid].owner_prefs) &\
- X (mask))
- X
- X#define PREPEND(str, buf) \
- X { char copy [1024];\
- X RESET (copy);\
- X strcat (copy, buf);\
- X sprintf (buf, "%s%s", str, copy);\
- X }
- X
- X/*
- X System specific definitions:
- X*/
- X
- X#if defined (sequent) || defined (unknown_port)
- X# ifndef SEEK_SET
- X# define SEEK_SET 0
- X# endif
- X# ifndef SEEK_CUR
- X# define SEEK_CUR 1
- X# endif
- X#endif
- X
- X#if defined (_MINIX) || defined (ultrix) || defined (__NeXT__) || \
- X defined (apollo) || defined (i386)
- X# ifndef NO_LOCKS
- X# define NO_LOCKS
- X# endif
- X# if !defined (bsd) && !defined (svr3) && !defined (svr4)
- X# define bsd
- X# endif
- X# ifndef ultrix
- X# undef GO_INTERACTIVE
- X# ifndef NO_ABORT_OP
- X# define NO_ABORT_OP
- X# endif
- X# endif
- X#endif
- X
- X#if defined (__convex__)
- X# ifdef __STDC__
- X# ifndef NO_LOCKS
- X# define NO_LOCKS
- X# endif
- X# endif
- X# ifdef GO_INTERACTIVE
- X# undef GO_INTERACTIVE
- X# ifndef NO_ABORT_OP /* Convex does define MSG_OOB, MSG_PEEK, SIOCATMARK */
- X# define NO_ABORT_OP
- X# endif
- X# endif
- X#endif
- X
- X#if defined (sun) || defined (hpux) || defined (__hpux) || \
- X defined (sequent) || defined (ultrix) || defined (__convex__) || \
- X defined (__NeXT__)
- X# if !defined (bsd) && !defined (svr3) && !defined (svr4)
- X# define bsd
- X# endif
- X#endif
- X
- X#if defined (sgi) || defined (__sgi) || defined (mips) || defined (__mips) ||\
- X defined (_AIX) || defined (stellar) || defined (titan) || defined (xenix) ||\
- X defined (sco) || defined (M_UNIX) || defined (M_XENIX) || defined (__osf__) \
- X || defined (stardent)
- X# if !defined (svr3) && !defined (svr4) && !defined (bsd)
- X# define svr3
- X# endif
- X# ifdef xenix
- X# ifndef NO_LOCKS
- X# define NO_LOCKS
- X# endif
- X# endif
- X# if defined (titan) || defined (stellar) || defined (stardent)
- X# ifdef GO_INTERACTIVE
- X# undef GO_INTERACTIVE
- X# endif
- X# ifndef NO_ABORT_OP
- X# define NO_ABORT_OP
- X# endif
- X# endif
- X#endif
- X
- X#if defined (i860) || defined (__DGUX__)
- X# if !defined (bsd) && !defined (svr3) && !defined (svr4)
- X# define svr4
- X# endif
- X#endif
- X
- X#define NONBLOCKING_IO
- X
- X#ifndef NO_ABORT_OP
- X# define VERSION "6.0c -- ListProcessor by Anastasios Kotsikonas"
- X#else
- X# define VERSION "6.0 -- ListProcessor by Anastasios Kotsikonas"
- X#endif
- X
- X/* If you do not have TCP/IP and are using Zmailer, provide the following
- X information about your host.
- X*/
- X#ifndef TCP_IP
- X# define HOSTNAME "localhost" /* Replace w/ your host's name */
- X# define LOCAL_ADDR "127.0.0.1" /* Replace w/ your host's IP address */
- X#endif
- X
- X/*
- X These functions don't have prototypes in SCO in the included files.
- X
- Xextern void exit (int);
- Xextern int unlink (char *);
- Xextern int stat (char *, struct stat *);
- Xextern int mkdir (char *, int);
- Xextern int lockf (int, int, int);
- Xextern int open (char *, int, ...);
- Xextern int creat (char *, int);
- Xextern int close (int);
- Xextern int getpid ();
- Xextern int stat (char *, struct stat *);
- Xextern int chmod (char *, int);
- Xextern int chdir (char *);
- Xextern int unlink (char *);
- Xextern unsigned int sleep (unsigned int);
- Xextern int execl (char *, ...);
- Xextern int read (int, void *, unsigned);
- Xextern int write (int, void *, unsigned);
- Xextern int umask (int);
- Xextern char *getenv (char *);
- Xextern void free (void *);
- Xextern int kill (int, int);
- Xextern int getuid (void);
- Xextern int abort (void);
- Xextern int access (char *, int);
- Xextern void *calloc (int, int);
- X*/
- *-*-END-of-src/defs.h-*-*
- echo x - src/global.h
- sed 's/^X//' >src/global.h <<'*-*-END-of-src/global.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- Xchar subscribersf [MAX_LINE];
- Xchar newsf [MAX_LINE];
- Xchar peersf [MAX_LINE];
- Xchar aliasesf [MAX_LINE];
- Xchar headersf [MAX_LINE];
- Xchar restrictedf [MAX_LINE];
- Xchar ignoredf [MAX_LINE];
- Xchar list_mail_f [MAX_LINE];
- Xchar list_moderated_f [MAX_LINE];
- Xchar report_listf [MAX_LINE];
- Xchar server_ignoredf [MAX_LINE];
- Xchar infof [MAX_LINE];
- Xchar welcomef [MAX_LINE];
- Xchar unprocessed_messages [MAX_LINE];
- Xchar unprocessed_subscribersf [MAX_LINE];
- Xchar unprocessed_peersf [MAX_LINE];
- Xchar unprocessed_newsf [MAX_LINE];
- Xchar unprocessed_digestf [MAX_LINE];
- Xchar message_idsf [MAX_LINE];
- Xchar message_id [MAX_LINE];
- Xchar digest_msgf [MAX_LINE];
- Xchar digest_timef [MAX_LINE];
- Xchar password_in_sub_file [MAX_LINE];
- Xchar **alternate_addresses;
- Xchar *prog;
- XSYS sys;
- XCOMMANDS commands [MAX_COMMANDS]; /* Set of recognizable commands */
- XREMOTE *rlists = NULL, *matched_rlists = NULL;
- XBOOLEAN debug = FALSE;
- X
- X/*
- X Below are the valid SET options, their valid values and their
- X default values.
- X*/
- X
- X/* valid SET options */
- Xchar *options [] = { "ADDRESS", "MAIL", "PASSWORD", "CONCEAL" };
- X
- X/* and values */
- Xchar *values [] =
- X{ "^FIXED$|^VARIABLE$", "^ACK$|^NOACK$|^POSTPONE$|^DIGEST$", ".*", "^YES$|^NO$" };
- X
- Xchar *default_values [] = { "FIXED", "NOACK", ".*", "NO" };
- X
- *-*-END-of-src/global.h-*-*
- echo x - src/ilp.h
- sed 's/^X//' >src/ilp.h <<'*-*-END-of-src/ilp.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X
- X Below are the #define's pertinent to ilp.c and silp.c
- X*/
- X
- X#include "ilpp.h"
- X
- X#define PORT 372 /* As assigned by IANA */
- X#define MAX_HOPS 5 /* ... from ILP server to ILP server */
- X#define TIMEOUT 180 /* How long to wait for server response */
- X#define MSGLEN 8
- X#ifndef BUFFSIZ
- X# define BUFFSIZ 8192
- X#endif
- X#ifndef RESET
- X# define RESET(v) (v[0] = EOS)
- X#endif
- X#define PRINTF(code, str) if (verbose) printf ("%d %s", code, str),\
- X fflush (stdout)
- X#ifndef MIN
- X# define MIN(a, b) ((a) < (b) ? (a) : (b))
- X#endif
- X
- X#define GENERAL_RESPONSES(cmd)\
- X{\
- X switch (cmd) {\
- X case OK: PRINTF (OK, "OK\n"); break;\
- X case CONNECT: PRINTF (CONNECT, "Connected\n"); break;\
- X case SYNTAX_ERROR: PRINTF (SYNTAX_ERROR, "Syntax error in request\n");\
- X break;\
- X case INVALID_REQ: PRINTF (INVALID_REQ, "Invalid request\n"); break;\
- X case PEER_UNAVAIL: PRINTF (PEER_UNAVAIL, "Peer unavailable\n"); break;\
- X case BAD_ARCHIVE: PRINTF (BAD_ARCHIVE, "Bad archive\n"); break;\
- X case RESTRICTED_REQ: PRINTF (RESTRICTED_REQ,\
- X "Restriction in force for request\n"); break;\
- X case NOT_OWNER: PRINTF (NOT_OWNER, "Invalid onwer\n"); break;\
- X case SYS_ERROR: PRINTF (SYS_ERROR, "System error\n"); break;\
- X case MESSAGE: PRINTF (MESSAGE, "Message\n"); break;\
- X case PERMISSION_DENIED: PRINTF (PERMISSION_DENIED, "Permission denied\n");\
- X break;\
- X case CONN_CLOSED: PRINTF (CONN_CLOSED, "Closing connection\n"); break;\
- X case CONN_ABORTED: PRINTF (CONN_ABORTED, "Connection aborted\n");\
- X return -1; break;\
- X case CONN_TIMEOUT: PRINTF (CONN_TIMEOUT, "Connection timed out\n");\
- X return -1; break;\
- X case SERVER_BUSY: PRINTF (SERVER_BUSY, "Server busy\n"); break;\
- X case PASSWORD_REQUIRED: PRINTF (PASSWORD_REQUIRED, "Password required\n");\
- X if (read_from_fd (sock_fd, nbytes, NULL) < 0) return -1; break;\
- X case CONTINUED: PRINTF (CONTINUED, "[Command incomplete:]"); break;\
- X case MORE_INPUT_REQUIRED: PRINTF (MORE_INPUT_REQUIRED,\
- X "[Command incomplete:]"); break;\
- X }\
- X}
- *-*-END-of-src/ilp.h-*-*
- echo x - src/ilpp.h
- sed 's/^X//' >src/ilpp.h <<'*-*-END-of-src/ilpp.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X
- X Define the Interactive ListProcessor Protocol.
- X*/
- X
- X#define OK 100
- X#define MORE_INPUT_REQUIRED 101
- X#define CONTINUED 102
- X#define PASSWORD_REQUIRED 103
- X#define CONNECT 105
- X#define MESSAGE 106
- X#define WRITE_TO_FILE_ASC 110
- X#define WRITE_TO_FILE_BIN 120
- X#define APPEND_TO_FILE_ASC 130
- X#define APPEND_TO_FILE_BIN 140
- X#define TEST_FILE_PERMISSIONS 154
- X#define SYNTAX_ERROR 200
- X#define INVALID_REQ 300
- X#define PEER_UNAVAIL 400
- X#define BAD_ARCHIVE 500
- X#define RESTRICTED_REQ 600
- X#define NOT_OWNER 700
- X#define SYS_ERROR 800
- X#define PERMISSION_DENIED 860
- X#define SERVER_BUSY 870
- X#define CONN_TIMEOUT 880
- X#define CONN_ABORTED 890
- X#define CONN_CLOSED 900
- *-*-END-of-src/ilpp.h-*-*
- echo x - src/list.h
- sed 's/^X//' >src/list.h <<'*-*-END-of-src/list.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X
- X Below are the #define's pertinent to list.c
- X
- X Preserve any quotes and new lines that appear below; change only path names.
- X
- X ALWAYS SPECIFY ABSOLUTE PATHS.
- X
- X*/
- X
- X#ifdef __NeXT__
- X# include "next.h"
- X#endif
- X
- X#ifndef GRACE_PERIOD
- X# define GRACE_PERIOD 604800 /* Time in secs after which offending */
- X /* addresses are removed/suspended */
- X#endif
- X#define ONE_MONTH 2592000 /* 30 days: error messages in the database */
- X /* older than this are removed */
- X#ifndef SHELL_CHAR_LIMIT
- X# define SHELL_CHAR_LIMIT 2048
- X#endif
- X#define INEWS_REPLY "/tmp/.inews.reply"
- X#define ERRORSF ".errors"
- X#define ERRORS2F ".errors.tmp"
- X#define UNPROC_TMP ".un.tmp"
- X#define MAIL_COPY ".messages"
- X#define MSG ".msg"
- X#undef MAILFORWARD
- X#define MAILFORWARD ".mailforward"
- X#define HEADER ".header"
- X#define MSG_NO ".msgno"
- X#define DIGEST_NO ".digestno"
- X#define CHECKSUMS ".sums"
- X#define REMOVED_USERS "removed.users"
- X#define REMOVED_ALIASES "removed.alias"
- X#define MBOX "mbox" /* Place to save list's messages */
- X#define ARCHIVE "archive" /* Public messages */
- X#define ORIGIN "^(Originator:[ \t])"
- X#define SENDER "^(Sender:[ \t])"
- X#define REPLY_TO "^(Reply-To:[ \t])"
- X#define DATE "^(Date:[ \t])"
- X#define TO "^(To:[ \t])"
- X#define CC "^(Cc:[ \t])"
- X#define KEYWORDS "^(Keywords:[ \t])"
- X#define ARCHIVE_NAME "^(archive-name:[ \t])"
- X#define CONTROL "^(Control:[ \t])"
- X#define NO_RECIPIENT_FILE "NONE"
- X#define MESSAGE_SEPARATOR \
- X"----------------------- Message requiring your approval ----------------------"
- X#define REQUESTS \
- X"(^[ \t]*APPR?O?V?E?[ \t]+([A-Z0-9.@-]+)[ \t]+.+[ \t]+[0-9]+[ \t]*$)|\
- X(^[ \t]*DISC?A?R?D?[ \t]+([A-Z0-9.@-]+)[ \t]+.+[ \t]+[0-9]+[ \t]*$)|\
- X(^[ \t]*EDIT[ \t]+([A-Z0-9.@-]+)[ \t]+.+[ \t]+[A-Z]+[ \t]*$)|\
- X(^[ \t]*GET[ \t]+[A-Z0-9/.-]+.+)|\
- X(^[ \t]*HELP[ \t]*[A-Z0-9]*$)|\
- X(^[ \t]*INDEX[ \t]*[A-Z0-9/.-]*.*)|\
- X(^[ \t]*INFO?R?M?A?T?I?O?N?[ \t]+([A-Z0-9.@-]+)[ \t]*$)|\
- X(^[ \t]*LIST?S?[ \t]*$)|\
- X(^[ \t]*PUT[ \t]+([A-Z0-9.@-]+)[ \t]+.+)|\
- X(^[ \t]*RECI?P?I?E?N?T?S?[ \t]+([A-Z0-9.@-]+)[ \t]*$)|\
- X(^[ \t]*REVI?E?W?[ \t]+([A-Z0-9.@-]+)[ \t]*$)|\
- X(^[ \t]*RELE?A?S?E?[ \t]*$)|\
- X(^[ \t]*REPO?R?T?S?[ \t]+([A-Z0-9.@-]+)[ \t]+.+$)|\
- X(^[ \t]*RUN[ \t]+([A-Z0-9.@-]+))|\
- X(^[ \t]*SET[ \t]+([A-Z0-9.@-]+))|\
- X(^[ \t]*STAT?I?S?T?I?C?S?[ \t]+([A-Z0-9.@-]+))|\
- X(^[ \t]*SUBS?C?R?I?B?E?[ \t]+([A-Z0-9.@-]+).+)|\
- X(^[ \t]*SYST?E?M?[ \t]+([A-Z0-9.@-]+)[ \t]+.+[ \t]+#.+)|\
- X(^[ \t]*UNSU?B?S?C?R?I?B?E?[ \t]*([A-Z0-9.@-]*))|\
- X(^[ \t]*SIGN?O?F?F?[ \t]*([A-Z0-9.@-]*))|\
- X(^[ \t]*REMOVE[ \t]ME)|\
- X(^[ \t]*PLEASE[ \t]+REMOVE[ \t]+)|\
- X(^[ \t]*PLEASE[ \t]+UNSU?B?S?C?R?I?B?E?[ \t]+)|\
- X(^[ \t]*PLEASE[ \t]+SIGN[ \t]+)|\
- X(^[ \t]*PLEASE[ \t]+ADD[ \t]+)|\
- X(^[ \t]*WHIC?H?[ \t]*$)|\
- X(^[ \t]*SHUTDOWN[ \t]+.+$)|\
- X(^[ \t]*RESTART[ \t]+.+$)|\
- X(^[ \t]*EXEC?U?T?E?[ \t]+.+#.+)"
- X
- X#define APPEND_TELNET(func) \
- X if ((sys.options & USE_TELNET)) {\
- X if ((f = fopen (mailforwardf, "a")) == NULL)\
- X report_progress (report, tsprintf ("%s(): Could not open %s", func, \
- X mailforwardf), TRUE),\
- X gexit (1);\
- X COMPLETE_FILE (f);\
- X fclose (f);\
- X }
- X
- X#define DELIVER_MAIL(recipient) \
- X if (!interactive) {\
- X if ((++mails_sent) >= MAX_EMAILS)\
- X mails_sent = 0,\
- X sleep (30);\
- X if (sys.options & USE_SYSMAIL) \
- X sysmail (mailforwardf); \
- X else \
- X syscom ("%s '%s' < %s", sys.mail.method, \
- X (((sys.options & USE_TELNET) == 0) ? locase (recipient) : " "), \
- X mailforwardf);\
- X }
- X
- X#define NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS(__address__, __func__, from_sender) \
- X { char error [MAX_LINE];\
- X report_progress (report, tsprintf ("Syntax error in user address: %s\n%s",\
- X __address__, (from_sender ? "Message not delivered to any recipients" : \
- X"Message not delivered to this recipient")), TRUE);\
- X create_header (&f, mailforwardf, sys.server.address, sys.server.address,\
- X sys.manager, "Syntax error in user address", TRUE, FALSE,\
- X TRUE);\
- X fprintf (f, "Error detected in user address: %s\n", __address__);\
- X if (from_sender)\
- X fprintf (f, "Message not distributed to list %s.\n",\
- Xsys.lists[listid].alias);\
- X else\
- X fprintf (f, "Message not delivered to this recipient.\n");\
- X fprintf (f, "The message is included below:\n\
- X-----------------------------------------------------------------------------\n\
- X");\
- X fclose (f);\
- X cat_append (headerf, mailforwardf);\
- X cat_append (msgf, mailforwardf);\
- X APPEND_TELNET (__func__);\
- X DELIVER_MAIL (sys.manager);\
- X }
- X
- X#define NOTIFY_OWNER_OF_MSG_IGNORED(__msg__, __sender__) \
- X{ \
- X report_progress (report, tsprintf (__msg__, __sender__), TRUE);\
- X create_header (&f, mailforwardf, sys.lists[listid].address, \
- X sys.lists[listid].address, sys.lists[listid].owner, \
- X "Notification: message ignored", FALSE, FALSE, FALSE);\
- X fprintf (f, __msg__, __sender__);\
- X fprintf (f, "\n\nThe message is included below:\n\
- X-----------------------------------------------------------------------------\n\
- X");\
- X fclose (f);\
- X cat_append (headerf, mailforwardf);\
- X cat_append (msgf, mailforwardf);\
- X APPEND_TELNET ("process_message");\
- X DELIVER_MAIL (sys.lists[listid].owner);\
- X}
- X
- X
- X#define REMOVE_ADDRESS(address, __from__, __to__, append_to) \
- X{\
- X FILE *fin, *fout;\
- X char line[MAX_LINE], linecopy[MAX_LINE], *error;\
- X long int len, written;\
- X OPEN_FILE (fin, __from__, "r", "process_message");\
- X OPEN_FILE (fout, __to__, "w", "process_message");\
- X while (!feof (fin)) {\
- X RESET (line);\
- X fgets (line, MAX_LINE - 2, fin);\
- X strcpy (linecopy, line);\
- X upcase (linecopy);\
- X if (line[0] != EOS) {\
- X if (linecopy[strlen (linecopy) - 1] == '\n')\
- X linecopy[strlen (linecopy) - 1] = EOS;\
- X if (removed || re_strcmp (address, linecopy, NULL) <= 0) {\
- X if ((written = write_to_fd (fileno (fout), line, (len = strlen (line))))\
- X < 0) {\
- X echo_append ((error = tsprintf ("write() failed; wrote %ld bytes \
- Xout of %ld requested to file %s; errno %d", abs (written), len, __to__, errno)), WARNING);\
- X if (sys.options & BSD_MAIL)\
- X syscom ("echo '%s' | %s -s 'write() failed; system shut down' %s",\
- X error, UCB_MAIL, sys.manager);\
- X gexit (16);\
- X }\
- X }\
- X else {\
- X if (line[strlen (line) - 1] == '\n')\
- X line[strlen (line) - 1] = EOS;\
- X echo_append (line, append_to);\
- X removed = TRUE;\
- X }\
- X }\
- X }\
- X fclose (fin);\
- X fclose (fout);\
- X}
- X
- X#define SUSPEND_ADDRESS(address, __from__, __to__) \
- X{\
- X FILE *fin, *fout;\
- X char line [MAX_LINE], linecopy [MAX_LINE], addr [MAX_LINE], *error;\
- X long int len, written;\
- X OPEN_FILE (fin, __from__, "r", "process_message");\
- X OPEN_FILE (fout, __to__, "w", "process_message");\
- X while (!feof (fin)) {\
- X RESET (line);\
- X fgets (line, MAX_LINE - 2, fin);\
- X strcpy (linecopy, line);\
- X upcase (linecopy);\
- X if (line[0] != EOS) {\
- X if (linecopy[strlen (linecopy) - 1] == '\n')\
- X linecopy[strlen (linecopy) - 1] = EOS;\
- X if (suspended || re_strcmp (address, linecopy, NULL) <= 0) {\
- X if ((written = write_to_fd (fileno (fout), line, (len = strlen (line))))\
- X < 0) {\
- X echo_append ((error = tsprintf ("write() failed; wrote %ld bytes \
- Xout of %ld requested to file %s; errno %d", abs (written), len, __to__, errno)), WARNING);\
- X if (sys.options & BSD_MAIL)\
- X syscom ("echo '%s' | %s -s 'write() failed; system shut down' %s",\
- X error, UCB_MAIL, sys.manager);\
- X gexit (16);\
- X }\
- X }\
- X else\
- X sscanf (line, "%s", addr),\
- X suspended = TRUE,\
- X fprintf (fout, "%s %s %s", addr, POSTPONE, skip_to_word (line, 3));\
- X }\
- X }\
- X fclose (fin);\
- X fclose (fout);\
- X}
- X
- X#ifdef GO_INTERACTIVE
- X# ifndef SYSLOG
- X# define IN_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0) {\
- X int val;\
- X while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
- X if (P (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error P(); errno %d", \
- X __func__, errno), TRUE),\
- X fclose (report),\
- X gexit (14);\
- X }
- X# else
- X# define IN_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0) {\
- X int val;\
- X while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
- X if (P (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error P(); errno %d", \
- X __func__, errno), TRUE),\
- X gexit (14);\
- X }
- X# endif
- X
- X# ifndef SYSLOG
- X# define OUT_OF_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0 && V (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error V(); errno %d", \
- X __func__, errno), TRUE),\
- X fclose (report),\
- X gexit (14);
- X# else
- X# define OUT_OF_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0 && V (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error V(); errno %d", \
- X __func__, errno), TRUE),\
- X gexit (14);
- X# endif
- X#endif
- X
- Xchar digest_tocf [MAX_LINE];
- Xchar mboxf [MAX_LINE];
- Xchar msg_nof [MAX_LINE];
- Xchar digest_nof [MAX_LINE];
- Xchar msgf [MAX_LINE];
- Xchar mailforwardf [MAX_LINE];
- Xchar archivef [MAX_LINE];
- Xchar headerf [MAX_LINE];
- Xchar mail_copyf [MAX_LINE];
- Xchar unprocessed_tmp [MAX_LINE];
- Xchar removed_usersf [MAX_LINE];
- Xchar removed_aliasesf [MAX_LINE];
- Xchar archive_name [MAX_LINE];
- Xchar limitsf [MAX_LINE];
- Xchar errorsf [MAX_LINE];
- Xchar errors2f [MAX_LINE];
- Xchar checksumsf [MAX_LINE];
- Xchar **multi_recipients; /* List of multiple recipient addresses */
- Xchar *list_alias = NULL; /* arg to the -L command option */
- Xchar *one_digest = NULL; /* arg to the -i command option */
- Xchar *mask, *archives_mask;
- Xchar hostname [256];
- X
- XFILE *mail = NULL; /* Source of messages */
- XFILE *report = NULL; /* Progress report to the administrator */
- XFILE *subscribers = NULL; /* List of subscribers */
- XFILE *news = NULL; /* List of newsgroups */
- XFILE *peers = NULL; /* List of peers */
- XFILE *restricted = NULL; /* List of people whose messages require special
- X handling */
- XFILE *ignored = NULL; /* List of people whose messages are ignored */
- XFILE *msg_no = NULL; /* Last message count */
- XFILE *digest_no = NULL; /* Last digest count */
- XFILE *headers = NULL; /* File containing headers of messages only */
- XFILE *message_ids = NULL; /* File containing message ids */
- X
- XBOOLEAN tty_echo = FALSE; /* -e option off */
- XBOOLEAN send_to_subscribers = TRUE; /* -r option off */
- XBOOLEAN execute_once = FALSE; /* -1 option off */
- XBOOLEAN errors_to_owner = FALSE; /* -f option off */
- XBOOLEAN multi_recip = FALSE; /* -m option off */
- XBOOLEAN force_digest = FALSE; /* -d option off */
- XBOOLEAN is_moderated = FALSE; /* -M option off */
- XBOOLEAN article_replies_to_author = FALSE; /* -p option off */
- XBOOLEAN message_replies_to_author = FALSE; /* -P option off */
- XBOOLEAN do_not_check_subscriptions = FALSE; /* -s option off */
- XBOOLEAN append_to_digest; /* gets set if anyone wants digests */
- XBOOLEAN message_rejected = FALSE;
- XBOOLEAN interactive = FALSE;
- XBOOLEAN no_compression = FALSE;
- X
- Xint returned_msg = 0; /* Counts the invalid messages */
- Xint public_msg = 0; /* Counts the public messages */
- Xint digest_msg = 0; /* Counts the digest messages */
- Xint mails_sent = 0; /* Counts email sent */
- Xint listid = -1;
- Xint maxrecipients = 0;
- Xint nlists = 0;
- Xint sid = -1;
- X
- Xtypedef struct _matched_prec_header {
- X char *line;
- X struct _matched_prec_header *next;
- X} MATCHED_PREC_HEADER;
- X
- XMATCHED_PREC_HEADER *matched_prec_header;
- X
- Xchar *mname[] = {
- X "jan", "feb", "mar", "apr", "may", "jun",
- X "jul", "aug", "sep", "oct", "nov", "dec",
- X};
- X
- X/* The following warnings assume that the user address follows the SMTP
- X code where () are present -- not safe with messages from BITNET mailers.
- X list.c will have to be altered. Code still under testing. */
- X
- Xchar *warnings = /* MAILER_DAEMON warnings */
- X"^421 ([^ \t]+)|\
- X^450 ([^ \t]+)|\
- X^451 ([^ \t]+)|\
- X^452 ([^ \t]+)|\
- X^501 ([^ \t]+)|\
- X^552 ([^ \t]+)|\
- X^554 NO[ \t]+SUCH[ \t]+USER:?([^ \t]+)&~HOST[ \t]+UNKNOWN.+AUTHORITATIVE.+ANSWER.+FROM.+NAME.+SERVER|\
- X^554 ([^ \t]+)&~HOST[ \t]+UNKNOWN.+AUTHORITATIVE.+ANSWER.+FROM.+NAME.+SERVER|\
- XCONNECTION[ \t]+TIMED|\
- XSERVICE[ \t]+UNAVAILABLE|\
- XNETWORK[ \t]+IS[ \t]+UNREACHABLE|\
- XUNKNOWN[ \t]+MAILER[ \t]+ERROR|\
- XCONNECTION[ \t]+RESET|\
- XREMOTE[ \t]+PROTOCOL[ \t]+ERROR|\
- XTIMEOUT.+WAITING[ \t]+FOR[ \t]+INPUT|\
- XPERMISSION[ \t]+DENIED|\
- XCONNECTION[ \t]+ABORTED|\
- XCONNECTION[ \t]+REFUSED|\
- XQUOTA[ \t]+EXCEEDED|\
- XDISK[ \t]+FULL|\
- XUNKNOWN[ \t]+DOMAIN|\
- XUNABLE.+SEND.+TO|\
- XHOST[ \t]+UNKNOWN&~AUTHORITATIVE.+ANSWER.+FROM.+NAME.+SERVER|\
- XNEVER.+HEARD.+OF.+HOST&~AUTHORITATIVE.+ANSWER.+FROM.+NAME.+SERVER|\
- XUNABLE[ \t]+TO[ \t]+SEND[ \t]+MAIL";
- X
- Xchar *errors = /* MAILER_DAEMON serious error messages */
- X"UNKNOWN[ \t]+USER[ \t]+([^ \t]+)[ \t]+AT[ \t]+NODE[ \t]+([^ \t]+)|\
- XNO[ \t]+SUCH[ \t]+USER[ \t]+([^ \t]+)[ \t]+AT[ \t]+NODE[ \t]+([^ \t]+)|\
- XUNKNOWN[ \t]+USER[ \t]+([^ \t]+)[ \t]+AT[ \t]+SITE[ \t]+([^ \t]+)|\
- XNO[ \t]+SUCH[ \t]+USER[ \t]+([^ \t]+)[ \t]+AT[ \t]+SITE[ \t]+([^ \t]+)|\
- XUNKNOWN[ \t]+USER|\
- XUSER[ \t]+UNKNOWN|\
- XHOST[ \t]+UNKNOWN.+AUTHORITATIVE.+ANSWER.+FROM.+NAME.+SERVER|\
- X^550 ";
- X
- Xchar *fatal_subjects = /* Serious error messages in Subject: lines */
- X"CAN.*T.+SEND.+FOR.+WEEK|\
- XCAN.*T.+SEND.+FOR[ \t]+([^ \t]+)[ \t]+DAYS";
- *-*-END-of-src/list.h-*-*
- echo x - src/listproc.h
- sed 's/^X//' >src/listproc.h <<'*-*-END-of-src/listproc.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X
- X Below are the #define's pertinent to listproc.c
- X
- X Preserve any quotes and new lines that appear below; change only path names.
- X
- X ALWAYS SPECIFY ABSOLUTE PATHS.
- X
- X*/
- X
- X#ifdef __STDC__
- X# include "ansi/listproc.h"
- X#else
- X# include "nonansi/listproc.h"
- X#endif
- X#ifdef __NeXT__
- X# include "next.h"
- X#endif
- X
- X#define UPDATE_DATE "July 12, 1994"
- X#define REV_LEVEL "6.0c/940712/0" /* Version/Original Release Date/Rev */
- X#define RECIP_FILE ".recip"
- X#define USERS_FILE "/tmp/users"
- X#define PEER_SERVER_REQUEST "Peer Server Request:"
- X#define START_OF_SIGNATURE "--"
- X#define ALIASES_TIMESTAMPF ".time.aliases"
- X#define IGNORED_TIMESTAMPF ".time.ignored"
- X#define INFO_TIMESTAMPF ".time.info"
- X#define SUBSCRIBERS_TIMESTAMPF ".time.subscrib"
- X#define WELCOME_TIMESTAMPF ".time.welcome"
- X#define NEWS_TIMESTAMPF ".time.news"
- X#define PEERS_TIMESTAMPF ".time.peers"
- X
- X#define DELIVER_MAIL(recipient, copy_owner) \
- X{\
- X if (fax_it) \
- X syscom ("%s < %s %s > /dev/null &", sys.fax.prog,\
- X mailforwardf, sys.fax.fax_no);\
- X else if (!interactive) {\
- X if ((++mails_sent) >= MAX_EMAILS)\
- X mails_sent = 0,\
- X sleep (30);\
- X if (sys.options & USE_SYSMAIL) \
- X sysmail (mailforwardf); \
- X else \
- X syscom ("%s '%s' '%s' < %s", sys.mail.method, \
- X (((sys.options & USE_TELNET) == 0) ? locase (recipient) : " "), \
- X ((copy_owner) ? \
- X ((listid >= 0 ? sys.lists[listid].owner : sys.manager)) \
- X : " "), mailforwardf);\
- X }\
- X}
- X
- X#define APPEND_TELNET(func) \
- X if (!interactive && !fax_it && (sys.options & USE_TELNET)) {\
- X if ((f = fopen (mailforwardf, "a")) == NULL)\
- X report_progress (report, tsprintf ("%s(): Could not open %s", func, \
- X mailforwardf), TRUE),\
- X gexit (1);\
- X COMPLETE_FILE (f);\
- X fclose (f);\
- X }
- X
- X#define NOTIFY_MANAGER(msg) \
- X{\
- X create_header (&f, mailforwardf, sys.server.address, sys.manager, sender,\
- X FALSE, OK, TRUE, FALSE);\
- X fprintf (f, "%s %s\n", msg, sender);\
- X COMPLETE_TELNET (f);\
- X fclose (f);\
- X DELIVER_MAIL (sys.manager, FALSE);\
- X report_progress (report, tsprintf ("%s %s; forwarding message to %s\n", msg,\
- Xsender, sys.manager), FALSE);\
- X}
- X
- X#define NOTIFY_MANAGER_OF_MSG_IGNORED(__msg__, __sender__, __func__) \
- X{ \
- X report_progress (report, tsprintf (__msg__, __sender__), TRUE);\
- X create_header (&f, mailforwardf, sys.server.address, sys.manager, \
- X "Notification: request not processed", FALSE, OK, FALSE, FALSE);\
- X fprintf (f, __msg__, __sender__);\
- X fprintf (f, "\n\nCheck the top level mbox file and the report file; \
- Xsender was %s\n", sender);\
- X fclose (f);\
- X APPEND_TELNET (__func__);\
- X DELIVER_MAIL (sys.manager, FALSE);\
- X}
- X
- X#define NOTIFY_OF_BAD_ARCHIVE(msg, archive, reply_code) \
- X{\
- X create_header (&f, mailforwardf, sys.server.address, sender, request,\
- X COPY_OWNER (ccerrors), reply_code, FALSE, TRUE);\
- X fprintf (f, msg, archive);\
- X COMPLETE_TELNET (f);\
- X fclose (f);\
- X DELIVER_MAIL (sender, COPY_OWNER (ccerrors));\
- X}
- X
- X#define NOTIFY_OF_REQUEST_FORWARDING \
- X{\
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,\
- X OK, FALSE, FALSE);\
- X if (interactive) {\
- X int ret;\
- X REMOTE *r = matched_rlists;\
- X fclose (f);\
- X while (r) {\
- X if (r->inet_addr[0] != EOS) {\
- X f = fopen (mailforwardf, "a");\
- X fprintf (f, "*** %s: Contacting ListProcessor %s @ %s, port %d ...\n",\
- X hostname, r->listproc, r->inet_addr, r->port);\
- X fclose (f);\
- X if ((ret = silp (r->inet_addr, r->port, sender, "", 60, mailforwardf,\
- X request)) < 0)\
- X reply_code (SYS_ERROR),\
- X f = fopen (mailforwardf, "a"),\
- X fprintf (f, "### %s: Local system error. Please send email.\n",\
- X hostname),\
- X fclose (f);\
- X else if (ret == PEER_UNAVAIL)\
- X f = fopen (mailforwardf, "a"),\
- X fprintf (f, "### %s: Peer unavailable. Please send email.\n",\
- X hostname),\
- X fclose (f);\
- X else if (ret == CONN_ABORTED)\
- X f = fopen (mailforwardf, "a"),\
- X fprintf (f, "### %s: Connection aborted. Please send email.\n",\
- X hostname),\
- X fclose (f);\
- X else if (ret == CONN_TIMEOUT)\
- X f = fopen (mailforwardf, "a"),\
- X fprintf (f, "### %s: Connection timed out. Please send email.\n",\
- X hostname),\
- X fclose (f);\
- X else if (ret == SERVER_BUSY)\
- X reply_code (SERVER_BUSY),\
- X f = fopen (mailforwardf, "a"),\
- X fprintf (f, "### %s: Remote server busy. Please send email.\n",\
- X hostname),\
- X fclose (f);\
- X else if (ret == SYS_ERROR)\
- X reply_code (SYS_ERROR),\
- X f = fopen (mailforwardf, "a"),\
- X fprintf (f, "### %s: Remote system error. Please send email.\n",\
- X hostname),\
- X fclose (f);\
- X }\
- X else\
- X f = fopen (mailforwardf, "a"),\
- X fprintf (f, "??? %s: ListProcessor %s cannot be contacted; please \
- Xsend email.\n", hostname, r->listproc),\
- X fclose (f);\
- X r = r->next;\
- X }\
- X return;\
- X }\
- X fprintf (f, "List %s is not local. Your request is forwarded to the \
- Xfollowing list\nserver(s):\n\n", sys.lists[nlists].alias);\
- X {\
- X REMOTE *r = matched_rlists;\
- X while (r)\
- X fprintf (f, "%s (List address: %s)\n", r->listproc, r->address),\
- X r = r->next;\
- X }\
- X fprintf (f, "\nYou may wish to send any such future requests to this/these \
- Xserver(s).\n");\
- X COMPLETE_TELNET (f);\
- X fclose (f);\
- X DELIVER_MAIL (sender, FALSE);\
- X}
- X
- X#define FORWARD_REQUEST \
- X {\
- X REMOTE *r = matched_rlists;\
- X while (r) {\
- X create_header (&f, mailforwardf, sender, r->listproc, "", FALSE, OK, \
- X FALSE, FALSE);\
- X fprintf (f, "%s\n", request);\
- X COMPLETE_TELNET (f);\
- X fclose (f);\
- X DELIVER_MAIL (r->listproc, FALSE);\
- X r = r->next;\
- X }\
- X }
- X
- X#define MEMBERS_ONLY \
- X{\
- X BOOLEAN ok_to_reset_address = FALSE;\
- X if ((sys.lists[listid].defaults.set_values[0][0] == EOS &&\
- X !strcmp (default_values [0], "VARIABLE")) ||\
- X (!strcmp (sys.lists[listid].defaults.set_values[0], "VARIABLE")))\
- X ok_to_reset_address = TRUE;\
- X create_header (&f, mailforwardf, sys.server.address, sender, request,\
- X COPY_OWNER (ccprivate), RESTRICTED_REQ, FALSE, FALSE);\
- X fprintf (f, "%s: List %s is private for members only.\nOnly subscribers may \
- Xissue this request.\n", sender, sys.lists[listid].alias);\
- X if (alternate_addresses) {\
- X fprintf (f, "\nIn addition, the system found the following \
- Xaddress(es) that resemble yours.\nIf one of these is you, please resend your \
- Xmessage from that one%s:\n\n",\
- X (ok_to_reset_address ? \
- X ", or use the\n'set <list> address' request to change the \
- Xaddress you are subscribed with" :\
- X ""));\
- X {\
- X int i;\
- X for (i = 0; alternate_addresses[i]; ++i)\
- X fprintf (f, "%s\n", alternate_addresses[i]),\
- X free ((char *) alternate_addresses[i]);\
- X free ((char **) alternate_addresses);\
- X alternate_addresses = NULL;\
- X fprintf (f, "\n");\
- X }\
- X }\
- X COMPLETE_TELNET (f);\
- X fclose (f);\
- X DELIVER_MAIL (sender, COPY_OWNER (ccprivate));\
- X}
- X
- X#define NOT_LIST_OWNER \
- X{\
- X reject_mail (sender, request, tsprintf ("%s: You are not the owner of this \
- Xlist\n", sender), NOT_OWNER, 0);\
- X if (!interactive) {\
- X create_header (&f, mailforwardf, sys.server.address,sys.lists[listid].owner,\
- X "WARNING: Hacker attack", FALSE, NOT_OWNER, TRUE, FALSE);\
- X fprintf (f, "The following request was sent to this ListProcessor by %s:\n\n%s\
- X\nThe password provided appears in the report file\n",\
- X sender, request);\
- X COMPLETE_TELNET (f);\
- X fclose (f);\
- X DELIVER_MAIL (sys.lists[listid].owner, FALSE);\
- X }\
- X}
- X
- X#define NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS(__address__) \
- X{\
- X report_progress (report, "Syntax error in user address\n", FALSE);\
- X create_header (&f, mailforwardf, sys.server.address, sys.manager,\
- X "Syntax error in user address", FALSE, SYNTAX_ERROR, TRUE,\
- X TRUE);\
- X if (request [0] != EOS)\
- X fprintf (f, ">%s\n", request);\
- X fprintf (f, "Error detected in user address: %s\nNo requests processed.\n",\
- X __address__);\
- X COMPLETE_TELNET (f);\
- X fclose (f);\
- X DELIVER_MAIL (sys.manager, FALSE);\
- X}
- X
- X#define NO_SUCH_MESSAGE_TAG(_tag_)\
- X{\
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,\
- X SYNTAX_ERROR, FALSE, TRUE);\
- X fprintf (f, "No message found with tag number %d.\n", _tag_);\
- X COMPLETE_TELNET (f);\
- X fclose (f);\
- X DELIVER_MAIL (sender, FALSE);\
- X}
- X
- X#define CANNOT_STAT_FILE(_file_, _symptom_)\
- X{\
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,\
- X SYS_ERROR, FALSE, TRUE);\
- X fprintf (f, "Cannot %s file %s.\nYour request has to be resubmitted.\n",\
- X_symptom_, _file_);\
- X COMPLETE_TELNET (f);\
- X fclose (f);\
- X DELIVER_MAIL (sender, FALSE);\
- X}
- X
- X#define COMMAND(index, _name_, _mask_, _func_)\
- X commands[index].name = _name_;\
- X commands[index].mask = _mask_;\
- X commands[index].func = (FUNC) _func_
- X
- X#define PUT_TIMESTAMP(_targetfile_, _stampfile_) \
- X stat (_targetfile_, &stat_buf);\
- X echo (tsprintf ("%d", stat_buf.st_mtime), _stampfile_)
- X
- X#define COPY_MESSAGE \
- X{\
- X char *error;\
- X long int len, written;\
- X sign[0] = RESET (line);\
- X signature = FALSE;\
- X sprintf (sign, "%s\n", START_OF_SIGNATURE);\
- X while (!feof (mail) && /* Copy till eof or next message */\
- X (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {\
- X if (!strcmp (line, sign))\
- X signature = TRUE;\
- X else if (!signature)\
- X if ((written = write_to_fd (fileno (f), line, (len = strlen (line)))) \
- X < 0) {\
- X echo_append ((error = tsprintf ("write() failed; wrote %ld bytes \
- Xout of %ld requested; errno %d", abs (written), len, errno)), WARNING);\
- X if (sys.options & BSD_MAIL)\
- X syscom ("echo '%s' | %s -s 'write() failed; system shut down' %s",\
- X error, UCB_MAIL, sys.manager);\
- X gexit (16);\
- X }\
- X RESET (line);\
- X fgets (line, MAX_LINE - 2, mail);\
- X }\
- X if (!strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))\
- X fseek (mail, -strlen (line), SEEK_CUR); /* Move back to beginning */\
- X}
- X
- X#ifdef GO_INTERACTIVE
- X# ifndef SYSLOG
- X# define IN_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0) {\
- X int val;\
- X while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
- X if (P (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error P(); errno %d",\
- X __func__, errno), TRUE),\
- X fclose (report),\
- X gexit (14);\
- X }
- X# else
- X# define IN_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0) {\
- X int val;\
- X while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
- X if (P (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error P(); errno %d",\
- X __func__, errno), TRUE),\
- X gexit (14);\
- X }
- X# endif
- X
- X# ifndef SYSLOG
- X# define OUT_OF_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0 && V (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error V(); errno %d",\
- X __func__, errno), TRUE),\
- X fclose (report),\
- X gexit (14);
- X# else
- X# define OUT_OF_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0 && V (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error V(); errno %d",\
- X __func__, errno), TRUE),\
- X gexit (14);
- X# endif
- X#endif
- X
- X#ifdef GO_INTERACTIVE
- X# define FORCE_EDIT \
- X OUT_OF_CRITICAL_SECTION ("put", SEM_LISTFILES);\
- X if (!interactive) /* No need to force EDIT for a live request */\
- X get_sys_files ("EDIT", params_copy, sender);
- X#else
- X# define FORCE_EDIT \
- X if (!interactive) /* No need to force EDIT for a live request */\
- X get_sys_files ("EDIT", params_copy, sender);
- X#endif
- X
- X#define CHECK_TIMESTAMP(_stampfile_, _targetfile_)\
- X if ((f = fopen (_stampfile_, "r")) != NULL) {\
- X fscanf (f, "%d\n", ×tamp);\
- X fclose (f);\
- X stat (_targetfile_, &stat_buf);\
- X if (stat_buf.st_mtime != timestamp) {\
- X create_header (&f, mailforwardf, sys.server.address, sender, request,\
- X FALSE, PERMISSION_DENIED, FALSE, TRUE);\
- X fprintf (f, "File %s has been modified since you last\nedited it. The \
- Xfile has to be reedited again.\n%s\
- XYour PUT request is returned to you unprocessed below:\
- X\n\n%s\n", _targetfile_, \
- X(!interactive ? \
- X"An EDIT request will be forced now and the new file will arrive \
- Xin a separate\nmessage.\n\n" : ""), \
- Xrequest);\
- X fflush (f);\
- X COPY_MESSAGE;\
- X COMPLETE_TELNET (f);\
- X fclose (f);\
- X DELIVER_MAIL (sender, FALSE);\
- X upcase (sender);\
- X FORCE_EDIT;\
- X return;\
- X }\
- X }
- X
- X#define REMOVE_ADDRESS(address, __from__, __to__) \
- X{\
- X FILE *fin, *fout;\
- X long int len, written;\
- X char line[MAX_LINE], linecopy[MAX_LINE], *error;\
- X BOOLEAN removed = FALSE;\
- X OPEN_FILE (fin, __from__, "r", "unsubscribe");\
- X OPEN_FILE (fout, __to__, "w", "unsubscribe");\
- X while (!feof (fin)) {\
- X RESET (line);\
- X fgets (line, MAX_LINE - 2, fin);\
- X strcpy (linecopy, line);\
- X upcase (linecopy);\
- X if (line[0] != EOS) {\
- X if (linecopy[strlen (linecopy) - 1] == '\n')\
- X linecopy[strlen (linecopy) - 1] = EOS;\
- X if (removed || re_strcmp (address, linecopy, NULL) <= 0) {\
- X if ((written = write_to_fd (fileno (fout), line, (len = strlen (line))))\
- X < 0) {\
- X echo_append ((error = tsprintf ("write() failed; wrote %ld bytes \
- Xout of %ld requested to file %s; errno %d", abs (written), len, __to__, errno)), WARNING);\
- X if (sys.options & BSD_MAIL)\
- X syscom ("echo '%s' | %s -s 'write() failed; system shut down' %s",\
- X error, UCB_MAIL, sys.manager);\
- X gexit (16);\
- X }\
- X }\
- X else\
- X removed = TRUE;\
- X }\
- X }\
- X fclose (fin);\
- X fclose (fout);\
- X}
- X
- X#define THANKS "THANK|GRACIAS|TODA|MERCI|DANK|ARIGATO|XIE.*XIE|DZENKUJEM|\
- XTAK|D'AKUJEM|MAHALO|BEDANKT|GROET|E.[XH]AR[IH]ST[OW]|SINCERELY|TRULY|LATER|\
- XSPOCIBO|END|QUIT"
- X
- X
- Xchar recipf [MAX_LINE]; /* path to list + RECIP_FILE */
- Xchar requests_file [MAX_LINE];
- Xchar original_params [10240];
- Xchar aliases_timestampf [MAX_LINE];
- Xchar ignored_timestampf [MAX_LINE];
- Xchar info_timestampf [MAX_LINE];
- Xchar subscribers_timestampf [MAX_LINE];
- Xchar welcome_timestampf [MAX_LINE];
- Xchar news_timestampf [MAX_LINE];
- Xchar peers_timestampf [MAX_LINE];
- X
- XFILE *mail = NULL; /* Source of messages */
- XFILE *report = NULL; /* Progress report to the administrator */
- XFILE *ignored = NULL; /* List of people whose messages are ignored */
- XFILE *msg_no = NULL; /* Last message count */
- XFILE *message_ids = NULL; /* List of message ids */
- X
- Xint sid = -1;
- Xint listid = -1;
- Xint request_no = 0; /* Counts the public messages */
- Xint nlists = -1; /* # of lists defined in CONFIG */
- Xint mails_sent = 0; /* Count mail sent */
- Xlong int restricted_commands = 0; /* Mask of restrictions */
- Xlong int disabled_commands = 0; /* Mask for disabling commands */
- Xlong int batched_commands = 0; /* Mask for batching commands */
- XBOOLEAN one_rejection = FALSE;
- XBOOLEAN restart_sys = FALSE;
- XBOOLEAN tty_echo = FALSE; /* -e option off */
- XBOOLEAN do_not_notify_peer_server = FALSE;
- XBOOLEAN peer_server_request = FALSE;
- XBOOLEAN process_batch = FALSE; /* -B option off */
- XBOOLEAN interactive = FALSE; /* -i option off */
- XBOOLEAN fax_it = FALSE;
- Xchar *mailforwardf = NULL;
- Xchar *replyf = NULL;
- Xchar hostname [256];
- X
- X/* Codes for helpful messages when a request is rejected. */
- X#define REJECT_LIST 1
- X#define REJECT_REQUEST 2
- X#define REJECT_NAME 3
- X#define REJECT_AT 4
- *-*-END-of-src/listproc.h-*-*
- echo x - src/next.h
- sed 's/^X//' >src/next.h <<'*-*-END-of-src/next.h-*-*'
- X/*
- X #define's specific to NeXT hosts.
- X*/
- X
- X#ifndef S_IRWXU
- X# define S_IRWXU 0000700 /* rwx, owner */
- X#endif
- X#ifndef S_IRUSR
- X# define S_IRUSR 0000400 /* read permission, owner */
- X#endif
- X#ifndef S_IWUSR
- X# define S_IWUSR 0000200 /* write permission, owner */
- X#endif
- X#ifndef S_IXUSR
- X# define S_IXUSR 0000100 /* execute/search permission, owner */
- X#endif
- X#ifndef S_IRWXG
- X# define S_IRWXG 0000070 /* rwx, group */
- X#endif
- X#ifndef S_IRGRP
- X# define S_IRGRP 0000040 /* read permission, group */
- X#endif
- X#ifndef S_IWGRP
- X# define S_IWGRP 0000020 /* write permission, grougroup */
- X#endif
- X#ifndef S_IXGRP
- X# define S_IXGRP 0000010 /* execute/search permission, group */
- X#endif
- X#ifndef S_IRWXO
- X# define S_IRWXO 0000007 /* rwx, other */
- X#endif
- X#ifndef S_IROTH
- X# define S_IROTH 0000004 /* read permission, other */
- X#endif
- X#ifndef S_IWOTH
- X# define S_IWOTH 0000002 /* write permission, other */
- X#endif
- X#ifndef S_IXOTH
- X# define S_IXOTH 0000001 /* execute/search permission, other */
- X#endif
- *-*-END-of-src/next.h-*-*
- echo x - src/pqueue.h
- sed 's/^X//' >src/pqueue.h <<'*-*-END-of-src/pqueue.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X
- X Below are the #define's pertinent to pqueue.c
- X
- X Preserve any quotes and new lines that appear below; change only path names.
- X
- X ALWAYS SPECIFY ABSOLUTE PATHS.
- X
- X*/
- X
- X#ifdef __NeXT__
- X# include "next.h"
- X#endif
- X
- XFILE *report = NULL; /* Progress report */
- XBOOLEAN tty_echo = FALSE; /* -e option off */
- Xint lfd = 2;
- Xint listid = -1; /* Dummy */
- Xint sid = -1;
- *-*-END-of-src/pqueue.h-*-*
- echo x - src/regexp.h
- sed 's/^X//' >src/regexp.h <<'*-*-END-of-src/regexp.h-*-*'
- X/*
- X * Definitions etc. for regexp(3) routines.
- X *
- X * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
- X * not the System V one.
- X */
- X#define NSUBEXP 10
- Xtypedef struct regexp {
- X char *startp[NSUBEXP];
- X char *endp[NSUBEXP];
- X char regstart; /* Internal use only. */
- X char reganch; /* Internal use only. */
- X char *regmust; /* Internal use only. */
- X int regmlen; /* Internal use only. */
- X char program[1]; /* Unwarranted chumminess with compiler. */
- X} regexp;
- X
- Xextern regexp *regcomp();
- Xextern int regexec();
- Xextern void regsub();
- Xextern void regerror();
- *-*-END-of-src/regexp.h-*-*
- echo x - src/regmagic.h
- sed 's/^X//' >src/regmagic.h <<'*-*-END-of-src/regmagic.h-*-*'
- X/*
- X * The first byte of the regexp internal "program" is actually this magic
- X * number; the start node begins in the second byte.
- X */
- X#define MAGIC 0234
- *-*-END-of-src/regmagic.h-*-*
- echo x - src/serverd.h
- sed 's/^X//' >src/serverd.h <<'*-*-END-of-src/serverd.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X
- X Below are the #define's pertinent to serverd.c
- X
- X ALWAYS SPECIFY ABSOLUTE PATHS.
- X
- X*/
- X
- X#ifdef __STDC__
- X# include "ansi/serverd.h"
- X#else
- X# include "nonansi/serverd.h"
- X#endif
- X
- X#ifdef __NeXT__
- X# include "next.h"
- X#endif
- X
- X#define MAX_TRIES 10 /* wait MAX_TRIES * 30 seconds */
- X
- XFILE *report = NULL;
- XBOOLEAN tty_echo = FALSE; /* -e option off */
- X
- Xstruct _list_limits {
- X char list_limitsf [MAX_LINE],
- X list_mail_f [MAX_LINE],
- X digest_msgf [MAX_LINE],
- X digest_timef [MAX_LINE];
- X int nmessages;
- X long int current_date;
- X BOOLEAN done_for_the_day;
- X} lists [MAX_LISTS];
- X
- Xchar *exit_string[] = { /* Define exit status strings */
- X/* 0 */ "OK",
- X/* 1 */ "Could not open or lock file",
- X/* 2 */ "SIGINT signal",
- X/* 3 */ "Command line option error",
- X/* 4 */ "Syntax error in file",
- X/* 5 */ "Could not spawn",
- X/* 6 */ "Shutdown request",
- X/* 7 */ "Restart request",
- X/* 8 */ "Received system signal",
- X/* 9 */ "Too many multiple recipients",
- X/* 10 */"Could not deliver mail",
- X/* 11 */"Malloc failed",
- X/* 12 */"Cannot fork",
- X/* 13 */"Socket connection problem",
- X/* 14 */"Semaphore error",
- X/* 15 */"Cannot setuid, setgid",
- X/* 16 */"Internal error",
- X/* 17 */"Unknown exit status"
- X};
- X
- X#ifdef GO_INTERACTIVE
- XBOOLEAN interactive = FALSE; /* -i option off */
- X#endif
- Xint lfd = 2;
- Xint nlists;
- Xint ppid;
- X
- X#ifndef WAIT3_NEEDS_UNION
- X# if defined (sequent) || defined (stardent) || defined (stellar) || \
- X defined (titan) || defined (unknown_port)
- X# ifdef WEXITSTATUS
- X# undef WEXITSTATUS
- X# endif
- X# ifdef WTERMSIG
- X# undef WTERMSIG
- X# endif
- X# ifdef WIFSIGNALED
- X# undef WIFSIGNALED
- X# endif
- X# ifdef WIFEXITED
- X# undef WIFEXITED
- X# endif
- X# endif
- X#endif
- X
- X#ifndef WEXITSTATUS
- X# define WEXITSTATUS(stat) ((int)(((stat)>>8)&0377))
- X#endif
- X
- X#ifdef GO_INTERACTIVE
- X# ifndef WTERMSIG
- X# define WTERMSIG(stat) (((int)((stat)&0377))&0177)
- X# endif
- X# ifndef WIFSIGNALED
- X# define WIFSIGNALED(stat) (((int)((stat)&0377))>0&&((int)(((stat)>>8)&\
- X 0377))==0)
- X# endif
- X# ifndef WIFEXITED
- X# define WIFEXITED(stat) (((int)((stat)&0377))==0)
- X# endif
- X# include "ilpp.h"
- X
- X# ifndef MAX_CONNECTIONS
- X# define MAX_CONNECTIONS 5
- X# endif
- X# define MSGLEN 8
- X# define TIMEOUT_SIG SIGUSR1 /* Signal sent when client is preempted */
- X# define ABORT_SIG SIGUSR2 /* Signal sent when server shuts down */
- X
- X# define LOGIN "email address [none]: "
- X# define PASSWORD "Password: "
- X# define PROMPT "request> "
- X# define CONT_PROMPT "> "
- X
- X# define MANAGER_LOGIN \
- X"You have logged in with manager privileges; you may not issue 'execute'\n\
- Xrequests.\n\n"
- X
- X# define OWNER_LOGIN \
- X"You have logged in with owner privileges; valid requests are:\n\n\
- Xhelp [topic]\n\
- Xset <list> [<option> <arg[s]>] -\n\
- X\toption: mail, password, address, conceal\n\
- X\targ for 'mail': ack/noack/postpone/digest\n\
- X\targs for 'password': <current-password> <new-password>\n\
- X\targs for 'address': <current-password> <new-address>\n\
- X\targ for 'conceal': yes/no\n\
- Xunsubscribe <list> - alias signoff\n\
- Xrecipients <list> - alias review\n\
- Xinformation <list>\n\
- Xstatistics <list> [subscriber email address(es)] [-all]\n\
- Xrun <list> [password cmd [args]]\n\
- Xlists\n\
- Xwhich\n\
- Xindex [archive | path-to-archive] [/password] [-all]\n\
- Xget <archive | path-to-archive> <file> [/password] [parts]\n\
- Xview <archive | path-to-archive> <file> [/password] [parts]\n\
- Xsearch <archive | path-to-archive> [/password] [-all] <pattern>\n\
- Xrelease\n\
- Xsystem <list> <password> <user-address> #user-request\n\
- Xreports <list> <password>\n\
- Xedit <list> <password> <file>\n\
- X\tfile: subscribers/aliases/news/peers/ignored/info/welcome\n\
- Xput <list> <password> <keyword> [args]\n\
- X\tkeyword:alias/ignore/subscribers/aliases/news/peers/ignored/info/welcome\n\
- X\targs:email address for alias/ignore\n\
- Xapprove <list> <password> <tag>\n\
- Xdiscard <list> <password> <tag>\n\n\
- XYou may replace the administrative <password> with -\n\
- XBuilt in commands are: quit/exit, ?/privileges, timeleft, binary, ascii\n\
- XRequests may be continued on another line if they are terminated with &\\n\n\
- XInput/output may be redirected with <, > and >>.\n\
- XUNIX pipes are formed with the \"|\" symbol.\n\
- XFor 'fax' requests, please send email.\n\
- XUsing BINARY as default transfer mode.\n\n"
- X
- X# define SUBSCRIBER_LOGIN \
- X"You have logged in with subscriber privileges; you may only issue the \
- Xfollowing\nrequests:\n\n\
- Xhelp [topic]\n\
- Xset <list> [<option> <arg[s]>] -\n\
- X\toption: mail, password, address, conceal\n\
- X\targ for 'mail': ack/noack/postpone/digest\n\
- X\targs for 'password': <current-password> <new-password>\n\
- X\targs for 'address': <current-password> <new-address>\n\
- X\targ for 'conceal': yes/no\n\
- Xunsubscribe <list> - alias signoff\n\
- Xrecipients <list> - alias review\n\
- Xinformation <list>\n\
- Xstatistics <list> [subscriber email address(es)] [-all]\n\
- Xrun <list> [password cmd [args]]\n\
- Xlists\n\
- Xwhich\n\
- Xindex [archive | path-to-archive] [/password] [-all]\n\
- Xget <archive | path-to-archive> <file> [/password] [parts]\n\
- Xview <archive | path-to-archive> <file> [/password] [parts]\n\
- Xsearch <archive | path-to-archive> [/password] [-all] <pattern>\n\
- Xrelease\n\n\
- X<current-password> can be replaced with -\n\
- XBuilt in commands are: quit/exit, ?/privileges, timeleft, binary, ascii\n\
- XRequests may be continued on another line if they are terminated with &\\n\n\
- XInput/output may be redirected with <, > and >>.\n\
- XUNIX pipes are formed with the \"|\" symbol.\n\
- XFor 'fax' requests, please send email.\n\
- XUsing BINARY as default transfer mode.\n\n"
- X
- X# define GENERAL_LOGIN \
- X"You have logged in as a casual user; you may only issue the following \
- Xrequests:\n\n\
- Xhelp [topic]\n\
- Xrecipients <list> - alias review\n\
- Xinformation <list>\n\
- Xstatistics <list> [subscriber email address(es)] [-all]\n\
- Xlists\n\
- Xindex [archive | path-to-archive] [/password] [-all]\n\
- Xget <archive | path-to-archive> <file> [/password] [parts]\n\
- Xview <archive | path-to-archive> <file> [/password] [parts]\n\
- Xsearch <archive | path-to-archive> [/password] [-all] <pattern>\n\
- Xrelease\n\n\
- XBuilt in commands are: quit/exit, ?/privileges, timeleft, binary, ascii\n\
- XRequests may be continued on another line if they are terminated with &\\n\n\
- XInput/output may be redirected with <, > and >>.\n\
- XUNIX pipes are formed with the \"|\" symbol.\n\
- XFor 'fax' requests, please send email.\n\
- XUsing BINARY as default transfer mode.\n\n"
- X
- X# define SERVER_BUSY_ \
- X"All interactive ListProcessor ports are busy. Please try again later.\n"
- X
- X# define GOOD_BYE \
- X"ListProcessor closing connection.\n"
- X
- X# define CONN_TIMED_OUT \
- X"Connection timed out.\n"
- X
- X# define SERVER_SHUTS_DOWN \
- X"Server shutting down.\n"
- X
- X# define REMOTE_SYS_ERROR \
- X"Remote system error.\n"
- X
- X# define MORE_INPUT \
- X"[Enter text below, end with a '.' in a line by itself; do not forget to\n\
- Xescape character sequences like | < >> >]\n"
- X
- X# define NULL_REDIRECT \
- X"Invalid null output redirect\n"
- X
- X# define BINARY_XFER \
- X"Transfer mode reset to binary\n"
- X
- X# define ASCII_XFER \
- X"Transfer mode reset to ASCII\n"
- X
- X# define SERVICING_OTHER_CONN \
- X"Server busy processing another request; please wait or hit ^C...\n"
- X
- X# define YOU_ARE_NEXT \
- X"Processing your request...\n"
- X
- X# define CLIENT_LOST(exitcode) \
- Xclose (msg_sock),\
- X_exit (exitcode)
- X
- X# define REPLY(msg_sock, code, bytes)\
- X{\
- X sprintf (reply, "%d %d \n", code, (bytes));\
- X if (write_to_fd (msg_sock, reply, strlen (reply)) < 0)\
- X CLIENT_LOST (13);\
- X}
- X
- X# define REPLY_ERROR(msg_sock, code, bytes, __msg__)\
- X{\
- X sprintf (reply, "%d %d \n%s", code, (bytes), __msg__);\
- X if (write_to_fd (msg_sock, reply, strlen (reply)) < 0)\
- X CLIENT_LOST (13);\
- X}
- X
- X# define REPLY_FILE(msg_sock, code, bytes, file)\
- X{\
- X sprintf (reply, "%d %d %s\n", code, (bytes), file);\
- X if (write_to_fd (msg_sock, reply, strlen (reply)) < 0)\
- X CLIENT_LOST (13);\
- X}
- X
- X# define CLOSE_CLIENT(msg_sock) \
- X if (msg_sock >= 0) {\
- X REPLY (msg_sock, CONN_CLOSED, strlen (GOOD_BYE));\
- X write_to_fd (msg_sock, GOOD_BYE, strlen (GOOD_BYE));\
- X close (msg_sock);\
- X }
- X
- X# define CANNOT_CONNECT(__msg__, __code__, __reply__) \
- X{\
- X sprintf (msg, "%d %d %s %d %d\n%d %d \n%s", CONNECT, conn_duration,\
- X version, strlen (PROMPT), strlen (CONT_PROMPT), __code__,\
- X strlen (__reply__), __reply__);\
- X write_to_fd (msg_sock, msg, strlen (msg));\
- X close (msg_sock);\
- X report_progress (report, __msg__, TRUE);\
- X}
- X
- X# define GET_LOGIN(buf) \
- X{\
- X ch = EOS;\
- X bytes_read = 0;\
- X while (ch != '\n' && bytes_read < MAX_LINE) {\
- X if (read (msg_sock, &ch, 1) <= 0 || ch == EOF)\
- X goto abort;\
- X if (time (0) - time_started > conn_duration)\
- X close_connection (TIMEOUT_SIG);\
- X buf [bytes_read++] = ((ch < ' ' && ch != '\t' && ch != '\n' && ch != '\r')\
- X|| (ch == (char) 127) ? ((char) 0) : ch);\
- X }\
- X buf [bytes_read] = EOS;\
- X clean_request (buf);\
- X l = 0;\
- X while (buf [l] != EOS) {\
- X if (buf [l] == '\n' || buf [l] == '\r')\
- X buf [l] = EOS;\
- X ++l;\
- X }\
- X}
- X
- X# define SET_NONBLOCKING(__func__) \
- X if (fcntl (msg_sock, F_SETFL, \
- X (mask = fcntl (msg_sock, F_GETFL, 0)) | O_NDELAY) < 0) \
- X report_progress (report,\
- X tsprintf ("\n%s(): fcntl() failed: errno %d",\
- X __func__, errno), TRUE);
- X
- X# define SET_BLOCKING(__func__) \
- X if (fcntl (msg_sock, F_SETFL, mask) < 0) \
- X report_progress (report,\
- X tsprintf ("\n%s(): fcntl() failed: errno %d",\
- X __func__, errno), TRUE);
- X
- X# define SEND_OOB_BYTE \
- X{ int value;\
- X do {\
- X errno = 0;\
- X value = send (msg_sock, "#", 1, MSG_OOB);\
- X } while (value < 0 && errno == ENOBUFS);\
- X if (value < 0 && errno != ENOBUFS)\
- X report_progress (report,\
- X tsprintf ("\nprocess_live_request(): \
- Xsend() failed: errno %d", errno), TRUE);\
- X}
- X
- X# define SEND_MSG \
- X{ int value;\
- X do {\
- X errno = 0;\
- X value = send (msg_sock, urgmsg, MSGLEN, NULL);\
- X } while (value < 0 && errno == ENOBUFS);\
- X if (value < 0 && errno != ENOBUFS)\
- X report_progress (report,\
- X tsprintf ("\nprocess_live_request(): \
- Xsend() failed: errno %d", errno), TRUE);\
- X}
- X
- X# define CHECK_CRITICAL_SECTION(__func__, msg_sock, __mask__) \
- X{\
- X char msg [256], ch;\
- X long int time_started, delay = 0, value;\
- X\
- X time (&time_started);\
- X while (interactive && msg_sock && (value = semctl (sid, 0, GETVAL)) >= 0 &&\
- X (value & (__mask__))) {\
- X REPLY (msg_sock, MESSAGE, strlen (SERVICING_OTHER_CONN));\
- X write_to_fd (msg_sock, SERVICING_OTHER_CONN,strlen (SERVICING_OTHER_CONN));\
- X --time_started;\
- X while (((time (0) - time_started) % 10) && (value = semctl (sid, 0, GETVAL)) >= 0 &&\
- X (value & (__mask__))) {\
- X SET_NONBLOCKING (__func__);\
- X if ((value = recv (msg_sock, &ch, 1, MSG_OOB)) > 0)\
- X if (ch == '\03') {\
- X sprintf (urgmsg, "%08d", 0);\
- X SET_BLOCKING (__func__);\
- X SEND_OOB_BYTE;\
- X SEND_MSG;\
- X already_aborted = TRUE;\
- X REPLY (msg_sock, OK, strlen (PROMPT));\
- X goto Skip;\
- X }\
- X else\
- X report_progress (report,\
- X tsprintf ("\n%s(): \
- Xrecv(): unexpected char %c", __func__, ch), TRUE);\
- X else if (value < 0 && errno && errno != EWOULDBLOCK &&\
- X errno != EAGAIN && errno != EINTR && errno != EINVAL)\
- X report_progress (report,\
- X tsprintf ("\n%s(): \
- Xrecv() failed: errno %d", __func__, errno), TRUE);\
- X SET_BLOCKING (__func__);\
- X }\
- X delay = 1;\
- X }\
- X if (delay) {\
- X REPLY (msg_sock, MESSAGE, strlen (YOU_ARE_NEXT));\
- X write_to_fd (msg_sock, YOU_ARE_NEXT, strlen (YOU_ARE_NEXT));\
- X }\
- X}
- X
- Xtypedef struct {
- X long int pid, /* Client pid */
- X time, /* Time connection established */
- X connid; /* Client id */
- X char name [MAX_LINE]; /* Remote host's IP address or name */
- X} CLIENT;
- X
- XCLIENT clients [MAX_CONNECTIONS];
- X
- Xlong int chpid, nforks, sock_fd, msg_sock;
- Xint sid, connid, conn_duration;
- Xstruct passwd *pwentry;
- Xchar requests_file [MAX_LINE], mailforwardf [MAX_LINE];
- Xchar urgmsg [MSGLEN + 1];
- X
- XBOOLEAN chdied = FALSE;
- X#endif
- *-*-END-of-src/serverd.h-*-*
- echo x - src/start.h
- sed 's/^X//' >src/start.h <<'*-*-END-of-src/start.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X
- X Below are the #define's pertinent to start.c
- X
- X Preserve any quotes that appear below; change only path names.
- X
- X ALWAYS SPECIFY ABSOLUTE PATHS.
- X
- X*/
- X
- X#ifdef __STDC__
- X# include "ansi/start.h"
- X#else
- X# include "nonansi/start.h"
- X#endif
- X
- X#ifdef __NeXT__
- X# include "next.h"
- X#endif
- X
- X#define MODERATED_MAIL_FILE "moderated"
- X
- X#define START_ABORT \
- X fprintf (stderr, "### start aborted; system not started. ###\n"),\
- X exit (1);
- X
- X#define DEFAULT_ALIASES \
- X"^@.*:(.*)@(.*\\..*) \\1@\\2"
- X
- Xchar report_list_accf [MAX_LINE];
- Xchar *pids [] = { PID_LIST, PID_SERVERD, PID_PQUEUE, PID_QUEUED, NULL };
- Xchar *mask;
- XBOOLEAN tty_echo = TRUE;
- XFILE *report = NULL;
- Xint sid = -1;
- *-*-END-of-src/start.h-*-*
- echo x - src/struct.h
- sed 's/^X//' >src/struct.h <<'*-*-END-of-src/struct.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- Xtypedef struct _prec_header { /* Header lines to be saved */
- X char *line;
- X struct _prec_header *next;
- X} PRECIOUS_HEADER;
- X
- Xtypedef struct _unix_cmds {
- X char password [MAX_LINE], /* Password for this command */
- X name [MAX_LINE], /* Name of the command users may execute */
- X *cmd, /* Actual command to execute */
- X *comment; /* Syntax message, or any other message */
- X struct _unix_cmds *next; /* Pointer to next structure */
- X} _CMDS;
- X
- Xtypedef struct {
- X char set_values [MAX_SET_OPTIONS][MAX_LINE];
- X} DEFAULTS;
- X
- Xtypedef struct {
- X struct {
- X char alias [MAX_LINE], /* As it appears in the aliases file */
- X comment [MAX_LINE], /* Comment: line in the outgoing mail message */
- X address [MAX_LINE], /* Full email address of the list */
- X owner [MAX_LINE], /* Email address of the list's owner */
- X password [MAX_LINE], /* Password that owner uses */
- X cmdoptions [MAX_LINE], /* List-specific command line options */
- X arch_dir [MAX_LINE], /* Directory to put archive files in */
- X farch_dir [MAX_LINE], /* " in which to record archive in DIR */
- X arch_spec [MAX_LINE], /* Specifies name of archive files */
- X arch_pass [MAX_LINE]; /* Password (if any) for the archive */
- X int owner_prefs, /* Owner preferences */
- X disabled_commands, /* Mask of disabled commands for this list */
- X digest_lines, /* Max number of lines in digest */
- X digest_hours, /* Send out digest every so many hours */
- X ncmds, /* Count of commands that may be executed*/
- X max_messages, /* Maximum number of messages per day */
- X options; /* Mask of options: autosub, conceal, archive */
- X PRECIOUS_HEADER *header; /* Precious header lines */
- X _CMDS *unix_cmds; /* commands that users may execute */
- X DEFAULTS defaults; /* Default list settings */
- X } lists [MAX_LISTS]; /* Structure for each list */
- X struct {
- X char address [MAX_LINE], /* Full email address of the server */
- X comment [MAX_LINE], /* Comment: line in the outgoing mail message */
- X cmdoptions [MAX_LINE], /* ListProcessor-specific command line options */
- X password [MAX_LINE]; /* For 'shutdown', 'restart' and 'execute' */
- X int manager_prefs; /* System manager preferences */
- X } server; /* Structure for the server */
- X struct {
- X char *method, /* Mail method to use */
- X env_var [MAX_LINE], /* Environment variable to use */
- X mail_prog [MAX_LINE], /* Which mail program to use */
- X precedence [MAX_LINE]; /* Which mail precedence to use */
- X } mail; /* Mail method structure */
- X struct {
- X long int msg, /* Maximum message limit in bytes */
- X files; /* Maximum file size before auto splitting */
- X } limits; /* Various limits are defined here */
- X struct {
- X unsigned int start,
- X stop;
- X } batch; /* When to batch requests */
- X struct {
- X char prog [MAX_LINE], /* Faxing program */
- X fax_no [MAX_LINE]; /* Fax number */
- X } fax;
- X char serverd_cmdoptions [MAX_LINE],/* Command line options */
- X manager [MAX_LINE], /* Manager of the system */
- X arg [MAX_LINE], /* Temporary storage */
- X organization [MAX_LINE]; /* Organization's name */
- X int users, /* Used by listproc when -r is given */
- X frequency; /* How often to read mail */
- X long int options; /* Various flags: BSD_PS, USE_TELNET, etc. */
- X} SYS;
- X
- Xtypedef void (*FUNC)();
- X
- Xtypedef struct {
- X char *name;
- X long int mask;
- X FUNC func;
- X} COMMANDS; /* Structure for requests */
- X
- Xtypedef struct remote {
- X char alias [MAX_LINE],
- X address [MAX_LINE],
- X comment [MAX_LINE],
- X listproc [MAX_LINE],
- X inet_addr [MAX_LINE];
- X int port;
- X struct remote *next;
- X} REMOTE; /* Structure for remote lists */
- *-*-END-of-src/struct.h-*-*
- echo x - src/sysmail.h
- sed 's/^X//' >src/sysmail.h <<'*-*-END-of-src/sysmail.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991/92, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#ifdef __STDC__
- X#include "ansi/sysmail.h"
- X#else
- X#include "nonansi/sysmail.h"
- X#endif
- X
- X#include <errno.h>
- X
- X#define PORT 25 /* sendmail port */
- X#define TIMEOUT 600 /* 10 mins timeout connecting to sendmail */
- X#define CONN_TIMEOUT -1
- X#define MAX_CALLS 1 /* if > 1, retry delivery that many times */
- X#ifndef SENDMAIL_HOST
- X#define SENDMAIL_HOST "localhost"
- X#endif
- X
- X/* List of SMTP commands recognized */
- X
- X#define ACKNOWLEDGE 220
- X#define CLOSE_CONNECTION 221
- X#define OK 250
- X#define WILL_FORWARD 251
- X#define DATA 354
- X#define SERVICE_UNAVAIL 421
- X#define PERMISSION_DENIED 450
- X#define HOST_ABORTED 451
- X#define DISK_FULL 452
- X#define NOT_RECOGNIZED 500
- X#define SYNTAX_ERROR 501
- X#define CMD_NOT_IMPL 502
- X#define BAD_SEQUENCE 503
- X#define PARAM_NOT_IMPL 504
- X#define USER_UNKNOWN 550
- X#define USER_NOT_LOCAL 551
- X#define TOO_MUCH_DATA 552
- X#define USER_AMBIGUOUS 553
- X#define TRANS_FAILED 554
- X#define END_OF_TEXT ".\n"
- X
- X#define CLOSEF \
- X fclose (msg),\
- X close (sock_fd)
- X
- X#define NOTIFY_MANAGER(error) \
- X if (sys.options & BSD_MAIL)\
- X syscom ("echo '%s' | %s -s 'Error during message delivery: ' %s &",\
- X error, UCB_MAIL, sys.manager)
- X
- X#define WARN_MANAGER_AND_OWNER(warning) \
- X if (sys.options & BSD_MAIL) {\
- X syscom ("echo '%s' | %s -s '%s: Warning during message delivery: ' %s &",\
- X warning, UCB_MAIL,\
- X(listid < 0 ? "LISTPROC" : sys.lists[listid].alias), sys.manager);\
- X if (listid >= 0 && strcmp (sys.manager, sys.lists[listid].owner))\
- X syscom ("echo '%s' | %s -s '%s: Warning during message delivery: ' %s &",\
- X warning, UCB_MAIL,\
- X(listid < 0 ? "LISTPROC" : sys.lists[listid].alias), sys.lists[listid].owner);\
- X }
- X
- X#define ABORT_CONNECTION \
- X if ((int) write (sock_fd, "QUIT\n", 5) < 5)\
- X report_progress (report, "_sysmail(): WARNING: Error writing to \
- Xsocket, while closing connection", TRUE);\
- X if (debug)\
- X fprintf (sent, "QUIT\n[ transaction aborted ]\n"),\
- X fflush (sent);\
- X cmd = server_response (sock_fd);
- X
- X#define CHECK_SERVER_RESPONSE(cmd, arg, cont)\
- X if (cmd != OK && cmd != arg) {\
- X char error [1024];\
- X if (cmd == SYNTAX_ERROR || cmd == TRANS_FAILED ||\
- X cmd == NOT_RECOGNIZED) {\
- X sprintf (error, "_sysmail(): Command: %snot recognized by sendmail.\
- X\n%s\nCould not deliver mail", buf, message);\
- X report_progress (report, error, TRUE);\
- X NOTIFY_MANAGER (error);\
- X ABORT_CONNECTION;\
- X queue = TRUE;\
- X goto abort;\
- X }\
- X else if (cmd == CMD_NOT_IMPL || cmd == PARAM_NOT_IMPL) {\
- X sprintf (error, "_sysmail(): Command: %snot implemeted.\n%s\n\
- XCould not deliver mail", buf, message);\
- X report_progress (report, error, TRUE);\
- X NOTIFY_MANAGER (error);\
- X ABORT_CONNECTION;\
- X queue = TRUE;\
- X goto abort;\
- X }\
- X else if (cmd == BAD_SEQUENCE) {\
- X sprintf (error, "_sysmail(): Command: %sissued too soon.\
- X\n%s\nCould not deliver mail", buf, message);\
- X report_progress (report, error, TRUE);\
- X NOTIFY_MANAGER (error);\
- X ABORT_CONNECTION;\
- X queue = TRUE;\
- X goto abort;\
- X }\
- X else if (cmd == SERVICE_UNAVAIL || cmd == HOST_ABORTED) {\
- X sprintf (error, "_sysmail(): Service unavailable.\
- X\n%s\nCould not deliver mail", message);\
- X report_progress (report, error, TRUE);\
- X NOTIFY_MANAGER (error);\
- X ABORT_CONNECTION;\
- X queue = TRUE;\
- X goto abort;\
- X }\
- X else if (cmd == DISK_FULL) {\
- X sprintf (error, "_sysmail(): File system full.\n%s\nCould not \
- Xdeliver mail", message);\
- X report_progress (report, error, TRUE);\
- X NOTIFY_MANAGER (error);\
- X ABORT_CONNECTION;\
- X queue = TRUE;\
- X goto abort;\
- X }\
- X else if (cmd == TOO_MUCH_DATA) {\
- X sprintf (error, "_sysmail(): Too many recipients or message \
- Xtoo long.\n%s\nCould not deliver mail", message);\
- X report_progress (report, error, TRUE);\
- X NOTIFY_MANAGER (error);\
- X ABORT_CONNECTION;\
- X queue = TRUE;\
- X goto abort;\
- X }\
- X else if (cmd == CONN_TIMEOUT) {\
- X sprintf (error, "_sysmail(): Connection timed out with %s. \
- XCould not deliver mail", SENDMAIL_HOST);\
- X report_progress (report, error, TRUE);\
- X NOTIFY_MANAGER (error);\
- X queue = TRUE;\
- X goto abort;\
- X }\
- X else if (cmd == USER_UNKNOWN) {\
- X sprintf (error, "_sysmail(): Address: %snot recognized.\n%s\nMessage \
- Xnot delivered to this recipient", buf, message);\
- X report_progress (report, error, TRUE);\
- X WARN_MANAGER_AND_OWNER (error);\
- X cont;\
- X }\
- X else if (cmd == USER_NOT_LOCAL) {\
- X sprintf (error, "_sysmail(): Address: %snot local; %s", buf, message);\
- X report_progress (report, error, TRUE);\
- X WARN_MANAGER_AND_OWNER (error);\
- X cont;\
- X }\
- X else if (cmd == USER_AMBIGUOUS) {\
- X sprintf (error, "_sysmail(): Address ambiguous: %s%s\nMessage not \
- Xdelivered to this address", buf, message);\
- X report_progress (report, error, TRUE);\
- X WARN_MANAGER_AND_OWNER (error);\
- X cont;\
- X }\
- X else if (cmd == PERMISSION_DENIED) {\
- X sprintf (error, "_sysmail(): Permission denied for address %s%s\n\
- XMessage not delivered to this recipient", buf, message);\
- X report_progress (report, error, TRUE);\
- X WARN_MANAGER_AND_OWNER (error);\
- X cont;\
- X }\
- X else if (cmd == WILL_FORWARD) {\
- X sprintf (error, "_sysmail(): Address: %snot local; %s", buf, message);\
- X report_progress (report, error, TRUE);\
- X WARN_MANAGER_AND_OWNER (error);\
- X cont;\
- X }\
- X else {\
- X sprintf (error, "_sysmail(): ERROR: Return value %d for command: %s%s\n\
- XPlease notify tasos@cs.bu.edu", cmd, buf, message);\
- X report_progress (report, error, TRUE);\
- X NOTIFY_MANAGER (error);\
- X if (call < MAX_CALLS)\
- X CLOSEF,\
- X sleep (60),\
- X _sysmail (file, call + 1);\
- X report_progress (report, "_sysmail(): ERROR: Could not deliver mail", \
- XTRUE);\
- X CLOSEF,\
- X gexit (10);\
- X }\
- X }
- X
- X#define WRITE_TO_SOCKET(sock_fd, buf)\
- X{ char bufcopy [1024];\
- X strcpy (bufcopy, buf);\
- X bytes_to_write = strlen (bufcopy);\
- X errno = 0;\
- X while ((bytes_written = write (sock_fd, bufcopy, strlen (bufcopy))) <\
- X bytes_to_write) {\
- X if (errno && errno != EWOULDBLOCK && errno != EAGAIN) {\
- X char error [MAX_LINE];\
- X switch (errno) {\
- X case EBADF: sprintf (error, "_sysmail(): Bad file number"); break;\
- X case EFAULT: sprintf (error, "_sysmail(): Bad address"); break;\
- X case EFBIG: sprintf (error, "_sysmail(): File limit reached"); break;\
- X case EINTR: sprintf (error, "_sysmail(): Received interrupt signal");\
- X break;\
- X case EINVAL: sprintf (error, "_sysmail(): Negative seek pointer");\
- X break;\
- X case EIO: sprintf (error, "_sysmail(): I/O error"); break;\
- X case ENOSPC: sprintf (error, "_sysmail(): No space left on device");\
- X break;\
- X case ENXIO: sprintf (error, "_sysmail(): No such device or address");\
- X break;\
- X case ERANGE: sprintf (error, "_sysmail(): Bytes to write (%d) out of \
- Xrange", bytes_to_write);\
- X break;\
- X default: sprintf (error, "_sysmail(): Error number %d", errno);\
- X }\
- X report_progress (report, error, TRUE);\
- X queue = TRUE;\
- X goto abort;\
- X }\
- X if (debug) {\
- X for (i = 0; i < bytes_written; fprintf (sent, "%c", bufcopy [i++]));\
- X fflush (sent);\
- X }\
- X if (bytes_written > 0)\
- X bytes_to_write -= bytes_written;\
- X if (bytes_written > 0)\
- X sprintf (bufcopy, "%s", bufcopy + bytes_written);\
- X errno = 0;\
- X }\
- X if (debug)\
- X fprintf (sent, "%s", bufcopy),\
- X fflush (sent);\
- X}
- X
- X#ifdef USE_CARRIAGE_RETURN_LINEFEED
- X# define CONVERT(__s__) \
- X{ \
- X char *r = strrchr (__s__, '\n');\
- X if (r) strcpy (r, "\r\n");\
- X}
- X#else
- X# define CONVERT(__s__)
- X#endif
- X
- X#define PROTOCOL(arg) \
- X while (!feof (msg) && cmd != arg) {\
- X RESET (buf);\
- X fgets (buf, MAX_LINE - 2, msg);\
- X CONVERT (buf);\
- X WRITE_TO_SOCKET (sock_fd, buf);\
- X if ((cmd = server_response (sock_fd)) == CONN_TIMEOUT) {\
- X queue = TRUE;\
- X goto abort;\
- X }\
- X CHECK_SERVER_RESPONSE (cmd, arg, continue);\
- X }
- X
- Xstatic char message [1024];
- Xstatic FILE *sent, *received;
- Xstatic BOOLEAN queue;
- *-*-END-of-src/sysmail.h-*-*
- echo x - src/ansi/catmail.h
- sed 's/^X//' >src/ansi/catmail.h <<'*-*-END-of-src/ansi/catmail.h-*-*'
- X#define LOST_REQUESTS PATH "/lost+found"
- X#define TAG_IDF PATH "/.tag.id"
- X#define CATMAIL_TMP PATH "/.catmail.tmp"
- *-*-END-of-src/ansi/catmail.h-*-*
- echo x - src/ansi/defs.h
- sed 's/^X//' >src/ansi/defs.h <<'*-*-END-of-src/ansi/defs.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define PATH "/usr/server"
- X#define WARNING PATH "/.warning"
- X#define REPORT_SERVER PATH "/.report.server"
- X#define REPORT_SERVERD PATH "/.report.daemon"
- X#define REPORT_PQUEUE PATH "/.report.pqueue"
- X#define REPORT_CATMAIL PATH "/.report.catmai"
- X#define CONFIG PATH "/config"
- X#define LIST PATH "/list -1 -L "
- X#define SERVER PATH "/listproc -1 "
- X#define SERVER_MAIL_FILE PATH "/requests"
- X#define BATCH_FILE PATH "/batch"
- X#define SERVERD PATH "/serverd"
- X#define PQUEUE PATH "/pqueue"
- X#define START PATH "/start"
- X#define OWNERSF PATH "/owners"
- X#define ALIASESF PATH "/.aliases"
- X#define SERVERD_LOCK_FILE PATH "/.lock.serverd"
- X#define PQUEUE_LOCK_FILE PATH "/.lock.pqueue"
- X#define PID_PQUEUE PATH "/.pid.pqueue"
- X#define PID_SERVERD PATH "/.pid.daemon"
- X#define PID_SERVER PATH "/.pid.server"
- X#define PID_LIST PATH "/.pid.list"
- X#define PID_QUEUED PATH "/.pid.queued"
- X#define MAILFORWARD PATH "/.mailforward"
- X#define ULISTPROCESSOR_REPLY PATH "/.reply"
- X#define ARCHIVE_DIR PATH "/archives"
- X#define OLD_SUBSCRIBERS PATH "/.oldsubscriber"
- X#define OLD_ALIASES PATH "/.oldaliases"
- X#define NEW_SUBSCRIBERS PATH "/.newsubscriber"
- X#define NEW_ALIASES PATH "/.newaliases"
- X#define TMP_LIVE PATH "/.live"
- *-*-END-of-src/ansi/defs.h-*-*
- echo x - src/ansi/listproc.h
- sed 's/^X//' >src/ansi/listproc.h <<'*-*-END-of-src/ansi/listproc.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define MAIL_COPY PATH "/.messages"
- X#define MSG_NO PATH "/.msgno"
- X#define AWK_PROG PATH "/.awk"
- X#define STATS_PROG PATH "/.stats"
- X#define SERVER_MBOX PATH "/mbox"
- X#define HELP_TOPICS PATH "/help/TOPICS"
- X#define STDOUT PATH "/stdout"
- X#define STDERR PATH "/stderr"
- X#define SETUP_MESSAGE_IDSF sprintf (message_idsf, "%s/%s", PATH, MESSAGE_IDS_F)
- X#define EXEC_STATS \
- X syscom ("%s %s %s %s %s %s", STATS_PROG, PATH, subscribersf,\
- X headersf, mailforwardf, params)
- X
- X#define REARRANGE_SUBSCRIBERS \
- X syscom ("%s/rev < %s | awk '{print $NF \"\\t\" $0}' | sort | \
- Xsed 's/^.*\t//' | %s/rev > %s/sub.%s", PATH, subscribersf,\
- X PATH, PATH, sys.lists[listid].alias);\
- X mv (tsprintf ("%s/sub.%s", PATH, sys.lists[listid].alias), subscribersf)
- X
- X#define CAT_FILE \
- X syscom ("%s %s | %s/fwin -n -o %ld -b %ld | sed -e 's/^From />From /' | \
- Xsed -e 's/^\\.$/\\\\./' >> %s", \
- X (compressed_source ? "zcat" : "cat"), fullname, PATH, offset,\
- X nbytes, mailforwardf)
- *-*-END-of-src/ansi/listproc.h-*-*
- echo x - src/ansi/misc.h
- sed 's/^X//' >src/ansi/misc.h <<'*-*-END-of-src/ansi/misc.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define SETUP_STRING sprintf (s, "%s/lists/%s/%s", PATH, alias, filename)
- X#define SETUP_IGNOREDF sprintf (server_ignoredf, "%s/%s", PATH, IGNORED)
- *-*-END-of-src/ansi/misc.h-*-*
- echo x - src/ansi/serverd.h
- sed 's/^X//' >src/ansi/serverd.h <<'*-*-END-of-src/ansi/serverd.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define LOAD_FILE PATH "/.load"
- X#define UNWANTED_HOSTSF PATH "/unwanted.hosts"
- X#define PRIVILEGED_HOSTSF PATH "/priv.hosts"
- X#define WELCOMEF PATH "/welcome.live"
- *-*-END-of-src/ansi/serverd.h-*-*
- echo x - src/ansi/start.h
- sed 's/^X//' >src/ansi/start.h <<'*-*-END-of-src/ansi/start.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define REPORT_SERVER_ACC PATH "/.rep.server.ac"
- X#define REPORT_SERVERD_ACC PATH "/.rep.serverd.a"
- X#define REPORT_START_ACC PATH "/.rep.start.acc"
- X#define REPORT_PQUEUE_ACC PATH "/.rep.pqueue.ac"
- X#define REPORT_START PATH "/.report.start"
- X#define CATMAIL PATH "/catmail"
- X#define SETUP_DIR sprintf (dir, "%s/lists/%s", PATH, sys.lists[i].alias)
- X#define SERVER_PIDS PID_SERVER ".*"
- X#define TMP_LIVE_FILES TMP_LIVE ".*"
- X#define REPLY_FILES ULISTPROCESSOR_REPLY "*"
- *-*-END-of-src/ansi/start.h-*-*
- echo x - src/ansi/sysmail.h
- sed 's/^X//' >src/ansi/sysmail.h <<'*-*-END-of-src/ansi/sysmail.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define SENT PATH "/sent"
- X#define RECEIVED_ PATH "/received"
- X#define IDF PATH "/.queue.id"
- X#define QUEUE_DIR PATH "/mqueue"
- *-*-END-of-src/ansi/sysmail.h-*-*
- echo x - src/nonansi/catmail.h
- sed 's/^X//' >src/nonansi/catmail.h <<'*-*-END-of-src/nonansi/catmail.h-*-*'
- X#define LOST_REQUESTS PATH/lost+found"
- X#define TAG_IDF PATH/.tag.id"
- X#define CATMAIL_TMP PATH/.catmail.tmp"
- *-*-END-of-src/nonansi/catmail.h-*-*
- echo x - src/nonansi/defs.h
- sed 's/^X//' >src/nonansi/defs.h <<'*-*-END-of-src/nonansi/defs.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define PATH "/usr/server
- X#define WARNING PATH/.warning"
- X#define REPORT_SERVER PATH/.report.server"
- X#define REPORT_SERVERD PATH/.report.daemon"
- X#define REPORT_PQUEUE PATH/.report.pqueue"
- X#define REPORT_CATMAIL PATH/.report.catmai"
- X#define CONFIG PATH/config"
- X#define LIST PATH/list -1 -L "
- X#define SERVER PATH/listproc -1 "
- X#define SERVER_MAIL_FILE PATH/requests"
- X#define BATCH_FILE PATH/batch"
- X#define SERVERD PATH/serverd"
- X#define PQUEUE PATH/pqueue"
- X#define START PATH/start"
- X#define OWNERSF PATH/owners"
- X#define ALIASESF PATH/.aliases"
- X#define SERVERD_LOCK_FILE PATH/.lock.serverd"
- X#define PQUEUE_LOCK_FILE PATH/.lock.pqueue"
- X#define PID_PQUEUE PATH/.pid.pqueue"
- X#define PID_SERVERD PATH/.pid.daemon"
- X#define PID_SERVER PATH/.pid.server"
- X#define PID_LIST PATH/.pid.list"
- X#define PID_QUEUED PATH/.pid.queued"
- X#define MAILFORWARD PATH/.mailforward"
- X#define ULISTPROCESSOR_REPLY PATH/.reply"
- X#define ARCHIVE_DIR PATH/archives"
- X#define OLD_SUBSCRIBERS PATH/.oldsubscriber"
- X#define OLD_ALIASES PATH/.oldaliases"
- X#define NEW_SUBSCRIBERS PATH/.newsubscriber"
- X#define NEW_ALIASES PATH/.newaliases"
- X#define TMP_LIVE PATH/.live"
- *-*-END-of-src/nonansi/defs.h-*-*
- echo x - src/nonansi/listproc.h
- sed 's/^X//' >src/nonansi/listproc.h <<'*-*-END-of-src/nonansi/listproc.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for:w profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define MAIL_COPY PATH/.messages"
- X#define MSG_NO PATH/.msgno"
- X#define AWK_PROG PATH/.awk"
- X#define STATS_PROG PATH/.stats"
- X#define SERVER_MBOX PATH/mbox"
- X#define HELP_TOPICS PATH/help/TOPICS"
- X#define STDOUT PATH/stdout"
- X#define STDERR PATH/stderr"
- X#define SETUP_MESSAGE_IDSF sprintf (message_idsf, "%s/%s", PATH", MESSAGE_IDS_F)
- X#define EXEC_STATS \
- X syscom ("%s %s %s %s %s %s", STATS_PROG, PATH", subscribersf,\
- X headersf, mailforwardf, params)
- X
- X#define REARRANGE_SUBSCRIBERS \
- X syscom ("%s/rev < %s | awk '{print $NF \"\\t\" $0}' | sort | \
- Xsed 's/^.*\t//' | %s/rev > %s/sub.%s", PATH", subscribersf,\
- X PATH", PATH", sys.lists[listid].alias);\
- X mv (tsprintf ("%s/sub.%s", PATH", sys.lists[listid].alias), subscribersf)
- X
- X#define CAT_FILE \
- X syscom ("%s %s | %s/fwin -n -o %ld -b %ld | sed -e 's/^From />From /' | \
- Xsed -e 's/^\\.$/\\\\./' >> %s", \
- X (compressed_source ? "zcat" : "cat"), fullname, PATH", offset,\
- X nbytes, mailforwardf)
- *-*-END-of-src/nonansi/listproc.h-*-*
- echo x - src/nonansi/misc.h
- sed 's/^X//' >src/nonansi/misc.h <<'*-*-END-of-src/nonansi/misc.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define SETUP_STRING sprintf (s, "%s/lists/%s/%s", PATH", alias, filename)
- X#define SETUP_IGNOREDF sprintf (server_ignoredf, "%s/%s", PATH", IGNORED)
- *-*-END-of-src/nonansi/misc.h-*-*
- echo x - src/nonansi/serverd.h
- sed 's/^X//' >src/nonansi/serverd.h <<'*-*-END-of-src/nonansi/serverd.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define LOAD_FILE PATH/.load"
- X#define UNWANTED_HOSTSF PATH/unwanted.hosts"
- X#define PRIVILEGED_HOSTSF PATH/priv.hosts"
- X#define WELCOMEF PATH/welcome.live"
- *-*-END-of-src/nonansi/serverd.h-*-*
- echo x - src/nonansi/start.h
- sed 's/^X//' >src/nonansi/start.h <<'*-*-END-of-src/nonansi/start.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define REPORT_SERVER_ACC PATH/.rep.server.ac"
- X#define REPORT_SERVERD_ACC PATH/.rep.serverd.a"
- X#define REPORT_START_ACC PATH/.rep.start.acc"
- X#define REPORT_PQUEUE_ACC PATH/.rep.pqueue.ac"
- X#define REPORT_START PATH/.report.start"
- X#define CATMAIL PATH/catmail"
- X#define SETUP_DIR sprintf (dir, "%s/lists/%s", PATH", sys.lists[i].alias)
- X#define SERVER_PIDS PATH/.pid.server.*"
- X#define TMP_LIVE_FILES PATH/.live.*"
- X#define REPLY_FILES PATH/.reply*"
- *-*-END-of-src/nonansi/start.h-*-*
- echo x - src/nonansi/sysmail.h
- sed 's/^X//' >src/nonansi/sysmail.h <<'*-*-END-of-src/nonansi/sysmail.h-*-*'
- X/*
- X AGREEMENT: This software can be used and distributed freely only as a
- X whole and not in parts, as long as you do not remove or alter the author
- X and copyright notices in the file defs.h; this notices are #define'd in
- X the symbols VERSION and COPYRIGHT. Although you may alter the code
- X provided for your personal use, you may not alter the functions
- X create_header(), create_multi_recipient_header() and main() in list.c,
- X listproc.c and serverd.c (where applicable), and you may not redistribute
- X any changes you may have made. No part of the source code bearing a
- X copyright notice can be included in commercial software systems without
- X written permission by the author.
- X By using this software you are bound by this agreement.
- X This software comes with no warranties and cannot be sold for profit.
- X The AGREEMENT and COPYRIGHT notices should be included in all source
- X files when distributing this software.
- X COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
- X Use, duplication or disclosure by the Federal Government is subject to the
- X restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
- X for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
- X*/
- X
- X#define SENT PATH/sent"
- X#define RECEIVED_ PATH/received"
- X#define IDF PATH/.queue.id"
- X#define QUEUE_DIR PATH/mqueue"
- *-*-END-of-src/nonansi/sysmail.h-*-*
- echo x - src/catmail.c
- sed 's/^X//' >src/catmail.c <<'*-*-END-of-src/catmail.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | CATMAIL UTILITY |
- X | |
- X | version 2.5 |
- X | |
- X | User contributed application. |
- X | Original author (1.0): Aad Nienhuis <Aad_Nienhuis@sconar.sco.uva.nl> |
- X | Modified by (1.1): Tasos Kotsikonas |
- X | Enhanced by (2.0): Tasos Kotsikonas, Warren Burstein |
- X | Enhanced by (2.1, 2.5): Tasos Kotsikonas |
- X ----------------------------------------------------------------------------
- X
- X This is a utility that appends a mail message supplied by sendmail in
- X stdin to the appropriate file, depending on the command line options
- X supplied. The application has to be setuid. If the incoming message
- X is for a moderated list and not from the moderator, append a NOTIFY request
- X to the requests file so that listproc will later notify the list owner,
- X soliciting his approval for posting the message.
- X
- X The utility is to be used primarily in the host's aliases file when
- X setting up aliases for various lists. To append to the system's requests
- X file it may be used as follows:
- X
- X listproc: "|HOMEDIR/catmail -r -f"
- X
- X To append to a list's mail file:
- X
- X list_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f"
- X
- X To append to a list's moderated file:
- X
- X list_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f -m"
- X
- X COMMAND LINE OPTIONS:
- X -L: The input is appened to the specified list's "mail" file.
- X -l: Same as -L.
- X -m: The input is appened to the specified list's "moderated" file.
- X and a copy is appended to the requests file to be forwarded
- X by listproc to the owner for approval.
- X -r: The input is appened to HOMEDIR/requests.
- X -f: The input is reformatted while appended.
- X*/
- X
- X#include <stdio.h>
- X#ifdef SYSLOG
- X# ifdef ultrix
- X# include <sys/syslog.h>
- X# else
- X# include <syslog.h>
- X# endif
- X#endif
- X#include <string.h>
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <signal.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <pwd.h>
- X#include <fcntl.h>
- X#include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X#include <time.h>
- X#include "defs.h"
- X#include "catmail.h"
- X#include "struct.h"
- X#include "global.h"
- X#if defined (__NeXT__) || defined (unknown_port)
- X# include "next.h"
- X#endif
- X
- X#ifdef __STDC__
- X# include <stdarg.h>
- Xextern char *tsprintf (char *, ...);
- X#else
- X# include <varargs.h>
- Xextern char *tsprintf ();
- X#endif
- Xextern int sys_config (FILE *, SYS *);
- Xextern void setup_string (char *, char *, char *);
- Xextern int _getopt (int, char **, char *);
- Xextern char *upcase (char *);
- Xextern int get_list_id (char *, SYS *, int);
- Xextern void report_progress (FILE *, char *, int);
- Xextern int lock_file (char *, int, int, BOOLEAN);
- Xextern void unlock_file (int);
- Xextern BOOLEAN extract_sender (char *);
- Xextern BOOLEAN owner_listed (char *, char *, char *, FILE *);
- Xextern int otoi (char *);
- Xextern int cat_append (char *, char *);
- Xextern int echo (char *, char *);
- Xextern BOOLEAN strinstr (char *, char *);
- X
- Xvoid main (int, char **, char **);
- Xvoid catmail (FILE *, FILE *, FILE *, FILE *, int);
- Xint get_tag_id (void);
- Xvoid usage (void);
- Xint gexit (int);
- X
- Xvoid main (int argc, char **argv, char **envp)
- X{
- X char *options = "rfml:L:", *getenv();
- X extern char *optarg;
- X extern int optopt;
- X#ifdef ultrix
- X time_t t;
- X#else
- X long int t;
- X#endif
- X int c, nlists, tag = 0;
- X char *list_alias = NULL, *mask;
- X char file [MAX_LINE];
- X char header [MAX_LINE];
- X char msg [MAX_LINE];
- X FILE *mail, *mailf = NULL, *pipe = NULL;
- X struct passwd *pwentry;
- X
- X while ((c = _getopt (argc, argv, options)) != EOF)
- X switch ((char) c) {
- X case 'm': moderated = TRUE; break;
- X case 'f': reformat = TRUE; break;
- X case 'r': requests = TRUE; moderated = FALSE; break;
- X case 'l':
- X case 'L': list_alias = upcase (optarg); break;
- X case ':':
- X fprintf (stderr, "catmail: Option '%c' requires an argument.\n",
- X optopt);
- X exit (3);
- X case '?':
- X default:
- X usage();
- X }
- X if ((mask = getenv ("ULISTPROC_UMASK")))
- X umask (otoi (mask));
- X else
- X mask = "066",
- X umask (S_IRWXG|S_IRWXO); /* 600 */
- X
- X signal (SIGALRM, (void (*)()) gexit);
- X alarm (120); /* Timeout after 2 mins */
- X#ifdef SYSLOG
- X openlog ("ListProcessor: catmail", LOG_NDELAY
- X# ifndef i386
- X |LOG_NOWAIT
- X# endif
- X , SYSLOG);
- X# ifndef ultrix
- X setlogmask (LOG_UPTO (LOG_INFO));
- X# endif
- X#else
- X if ((report = fopen (REPORT_CATMAIL, "a+")) == NULL)
- X fprintf (stderr, "catmail: Could not open %s\n", REPORT_CATMAIL),
- X exit (1);
- X chmod (REPORT_CATMAIL, 384);
- X#endif
- X
- X if ((pwentry = getpwuid (getuid ())) == NULL)
- X report_progress (report, "main(): Invalid user account", TRUE),
- X exit (3);
- X if (requests) /* Select file to append to */
- X tty_echo = FALSE,
- X report_progress (report, "\n--- NEW MAIL FOR LISTPROCESSOR ---\n", FALSE),
- X report_progress (report, tsprintf ("Access granted to user id %d (%s)",
- X getuid(), pwentry->pw_name), TRUE),
- X strcpy (file, SERVER_MAIL_FILE);
- X else {
- X if (list_alias == NULL)
- X report_progress (report, "\ncatmail: No list to process", TRUE),
- X exit (3);
- X nlists = sys_config (report, &sys);
- X if ((listid = get_list_id (list_alias, &sys, nlists)) < 0)
- X report_progress (report, tsprintf ("\ncatmail: Unknown list %s",
- X list_alias), TRUE),
- X exit (3);
- X setup_string (file, list_alias,
- X (moderated ? LIST_MODERATED_F : LIST_MAIL_FILE));
- X tty_echo = FALSE;
- X report_progress (report, tsprintf ("\n--- NEW MAIL FOR %s ---\n",
- X list_alias), FALSE);
- X report_progress (report, tsprintf ("Access granted to user id %d (%s)",
- X getuid(), pwentry->pw_name), TRUE);
- X setup_string (list_mail_f, list_alias, LIST_MAIL_FILE);
- X }
- X#ifndef NO_LOCKS
- X signal (SIGINT, (void (*)()) gexit);
- X if ((lfd = lock_file (file, O_RDWR | O_CREAT, 0640, TRUE)) < 0)
- X switch (lfd) {
- X case CANT_OPEN:
- X report_progress (report, tsprintf ("\nCould not stat file %s", file),
- X TRUE);
- X exit (1);
- X case CANT_LOCK:
- X if (requests)
- X strcpy (file, LOST_REQUESTS);
- X else
- X setup_string (file, list_alias, LOST_MAIL);
- X report_progress (report, tsprintf ("\nCANNOT LOCK FILE: SAVING UNDER %s",
- X file), TRUE);
- X }
- X if (moderated) { /* Also lock SERVER_MAIL_FILE and LIST_MAIL_FILE */
- X if ((lfd2 = lock_file (SERVER_MAIL_FILE, O_RDWR | O_CREAT, 0640, TRUE)) < 0)
- X switch (lfd2) {
- X case CANT_OPEN:
- X report_progress (report, tsprintf ("\nCould not stat file %s",
- X SERVER_MAIL_FILE), TRUE);
- X gexit (1);
- X case CANT_LOCK:
- X report_progress (report,
- X tsprintf ("\nCANNOT LOCK FILE %s: TAKING MY CHANCES",
- X SERVER_MAIL_FILE), TRUE);
- X }
- X if ((lfd3 = lock_file (list_mail_f, O_RDWR | O_CREAT, 0640, TRUE)) < 0)
- X switch (lfd3) {
- X case CANT_OPEN:
- X report_progress (report, tsprintf ("\nCould not stat file %s",
- X list_mail_f), TRUE);
- X gexit (1);
- X case CANT_LOCK:
- X report_progress (report,
- X tsprintf ("\nCANNOT LOCK FILE %s: TAKING MY CHANCES",
- X list_mail_f), TRUE);
- X }
- X }
- X#endif
- X OPEN_FILE (mail, file, "a+", "main");
- X sprintf (header, "/tmp/.%d.1.catmail", getpid());
- X sprintf (msg, "/tmp/.%d.2.catmail", getpid());
- X if (moderated) {
- X tag = get_tag_id();
- X OPEN_FILE (pipe, header, "w", "main");
- X t = time (0);
- X fprintf (pipe, "From %s %s\nNOTIFY\n\
- XApproval request from %s for posting \
- Xthe following\nmessage to moderated list %s. If approved, send the following \
- Xrequest to\n%s:\n\nAPPROVE %s <password> %d\n\n\
- XIf the message is to be discarded, reply with the following request:\n\n\
- XDISCARD %s <password> %d\n\n\
- X----------------------------- message follows ------------------------------\n",
- X sys.lists[listid].owner, ctime (&t), sys.server.address,
- X list_alias, sys.server.address, list_alias, tag, list_alias, tag);
- X fclose (pipe);
- X OPEN_FILE (pipe, msg, "w", "main");
- X OPEN_FILE (mailf, list_mail_f, "a+", "main");
- X }
- X catmail (stdin, mail, mailf, pipe, tag);
- X fclose (mail);
- X if (pipe)
- X fclose (pipe);
- X if (mailf)
- X fclose (mailf);
- X#ifdef SYSLOG
- X closelog ();
- X#else
- X fclose (report);
- X#endif
- X if (moderated) /* Message was not from moderator */
- X cat_append (header, SERVER_MAIL_FILE),
- X cat_append (msg, SERVER_MAIL_FILE);
- X unlink (header);
- X unlink (msg);
- X gexit (0);
- X}
- X
- X/*
- X Append the input file to the output file, possibly pipe it also to another
- X output file, and possibly reformat it.
- X Turn moderation flag off if the message is from one of the list owners.
- X*/
- X
- Xvoid catmail (FILE *in, FILE *out, FILE *mailf, FILE *copy, int tag)
- X{
- X char buf [MAX_LINE];
- X char sender [MAX_LINE];
- X
- X sender[0] = RESET (buf);
- X fgets (buf, MAX_LINE - 2, in); /* Do not format very first "From " line */
- X if (feof (in)) {
- X moderated = FALSE;
- X return;
- X }
- X strcpy (sender, buf);
- X
- X extract_sender (sender); /* Get sender; ignore address syntax correctness */
- X upcase (sender);
- X if (moderated &&
- X (owner_listed (OWNERSF, sender, sys.lists[listid].alias, report) ||
- X strinstr (MAILER_DAEMON, sender)))
- X out = mailf, /* Output file is now 'mail' instead of 'moderated' */
- X moderated = FALSE; /* Message from moderator */
- X fputs (buf, out);
- X if (moderated && !strncmp (buf, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))
- X fprintf (out, "Message-Tag: %d\n", tag),
- X fprintf (copy, ">%sMessage-Tag: %d\n", buf, tag);
- X RESET (buf);
- X while (!feof (in)) {
- X fgets (buf, MAX_LINE - 2, in);
- X if (buf[0] != EOS) {
- X if (reformat &&
- X !strncmp (buf, START_OF_MESSAGE, strlen (START_OF_MESSAGE))) {
- X putc ('>', out);
- X if (copy)
- X putc ('>', copy);
- X }
- X fputs (buf, out);
- X if (copy)
- X fputs (buf, copy);
- X }
- X RESET (buf);
- X }
- X}
- X
- X/*
- X Get unique tag id for moderated message.
- X*/
- X
- Xint get_tag_id ()
- X{
- X FILE *id;
- X int id_no = 1;
- X
- X if ((id = fopen (TAG_IDF, "r")) != NULL)
- X fscanf (id, "%d\n", &id_no),
- X fclose (id);
- X echo (tsprintf ("%d", id_no + 1), TAG_IDF);
- X return id_no;
- X}
- X
- Xvoid usage ()
- X{
- X fprintf (stderr, "Usage: catmail {<<-L | -l> LIST_ALIAS [-m]> | <-r>} [-f]]\n\
- X-L: Append to HOMEDIR/lists/LIST_ALIAS/mail.\n\
- X-l: Same -L.\n\
- X-m: Append to HOMEDIR/lists/LIST_ALIAS/moderated instead.\n\
- X-r: Append to HOMEDIR/requests instead.\n\
- X-f: Reformat messages before appending.\n\
- X");
- X exit (3);
- X}
- X
- X/*
- X Graceful exit.
- X*/
- X
- Xint gexit (int exitcode)
- X{
- X#ifndef NO_LOCKS
- X unlock_file (lfd);
- X unlock_file (lfd2);
- X unlock_file (lfd3);
- X#endif
- X exit (exitcode);
- X}
- *-*-END-of-src/catmail.c-*-*
- echo x - src/farch.c
- sed 's/^X//' >src/farch.c <<'*-*-END-of-src/farch.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | FILE ARCHIVING UTILITY |
- X | |
- X | Version 3.1 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X farch archives files into the specified directories, possibly splitting
- X them into smaller parts. It then updates the DIR file of the appropriate
- X archive. Split files have numbers appended to their original names;
- X non-split files have their names intact. Binary files are uuencoded before
- X processed, and all output files are compressed.
- X
- X COMMAND LINE OPTIONS:
- X -n: Do not split input files.
- X -t: Tar all input files.
- X -b: Input files are binary; uuencode.
- X -B: Input files are binary; do not uuencode, do not split.
- X -s: Set the maximum size of each of the split subparts in kilobytes.
- X -d: Specify the actual directory that the archived files will reside.
- X -p: Specify the password for the private archive.
- X -D: Specify a descriptive string to be appended to each DIR file.
- X -r: Remove the specified files from the specified archive.
- X -a: Specify the archive where the input files will be archived.
- X -Z: Turn of file compression.
- X -u: Update existing file.
- X
- X WARNING: The program can also archive directory files, if these can be
- X of any use.
- X
- X Algorithm:
- X {
- X Process command line arguments; allocate buffer_size
- X Open master archive and all subarchives as necessary to get to the
- X specified (path-to-) archive; get path to specified archive
- X Verify existsence of target directory -- create it if necessary
- X Tar files, if so requested
- X for (each input file) {
- X open
- X get filesize
- X if (-r)
- X remove file
- X else {
- X if (-b)
- X uuencode file
- X if (-n or filesize <= buffer_size) { -- Do not split --
- X if (-b)
- X copy uuencoded file into target directory
- X if (file does not exist in target directory)
- X copy it to target directory
- X compress it
- X update (archive's directory)
- X }
- X else split file {
- X while (not eof) {
- X get unique output filename
- X fwrite (leftover bytes from previous chunk)
- X fread (new chunk)
- X if (! -b) {
- X locate nearest newline from the end of the buffer
- X copy those skipped bytes to leftover
- X }
- X fwrite (new modified chunk)
- X compress it
- X }
- X fwrite (any leftovers)
- X compress part
- X update (archive's directory)
- X }
- X }
- X }
- X }
- X*/
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
- X && !defined (sequent) && !defined (unknown_port)
- X# include <malloc.h>
- X#endif
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <sys/stat.h>
- X#include <string.h>
- X#include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X#include <signal.h>
- X#include "defs.h"
- X#include "struct.h"
- X#include "global.h"
- X#include "listproc.h"
- X
- X#define DEFAULT_SIZE 64 * 1024
- X
- X#ifdef __STDC__
- X# include <stdarg.h>
- Xextern int syscom (char *, ...);
- X#else
- X# include <varargs.h>
- Xextern int syscom ();
- X#endif
- Xextern char *extract_filename (char *);
- Xextern char *locase (char *);
- X#ifndef __NeXT__
- Xextern long int atol (char *);
- X#else
- Xextern long int atol (const char *);
- X#endif
- Xextern int _getopt (int, char **, char *);
- Xextern BOOLEAN make_indexes (char *, char *, char *, char *, char *);
- Xextern BOOLEAN mkdir1 (char *, char *, char *);
- Xextern char *mystrdup (char *);
- Xextern int otoi (char *);
- X
- Xvoid main (int , char **);
- Xvoid uuencode (FILE **, char *, char *, struct stat *, BOOLEAN);
- Xint update (char *, char *, long int, long int *, char *, char *,
- X struct stat, BOOLEAN, BOOLEAN, BOOLEAN);
- Xvoid remove_files (char *, char *, long int, struct stat, BOOLEAN);
- Xvoid usage (void);
- Xvoid do_archive (int, int, char **, char *, char *, char *, char *, char *,
- X long int, BOOLEAN, BOOLEAN, BOOLEAN, BOOLEAN, BOOLEAN,
- X BOOLEAN);
- Xint get_archive (char **, char *, char *, BOOLEAN);
- Xint get_dir (char *, char **, char *);
- Xint tar_files (int, int, char **, char *);
- Xvoid rmfiles (int, int, char **, char *, BOOLEAN, BOOLEAN);
- Xint gexit (int);
- X
- Xchar *uue_file, *archives_mask, *comment;
- X
- Xvoid main (int argc, char **argv)
- X{
- X long int size = DEFAULT_SIZE;
- X char *buf, *arch = NULL, *newdir = NULL, *dir, fullpath[10240],
- X *tarf, *password = NULL, *options = "nbBs:a:d:t:p:D:urZU", *text = "";
- X int c;
- X BOOLEAN bin = FALSE, tar = FALSE, split = TRUE, uue = FALSE,
- X remove_files = FALSE, no_compression = FALSE, updatef = FALSE;
- X extern char *optarg, *getenv();
- X extern int optopt, optind;
- X
- X buf = (char *) malloc (size * sizeof (char));
- X dir = (char *) malloc (sizeof (char));
- X while ((c = _getopt (argc, argv, options)) != EOF)
- X switch ((char) c) {
- X case 'n': split = FALSE; break;
- X case 't': tar = TRUE; tarf = optarg;
- X case 'b': bin = TRUE; uue = TRUE; break;
- X case 'B': bin = TRUE; uue = FALSE; split = FALSE; break;
- X case 's': size = (long) atol (optarg) * 1024;
- X if (size <= 0)
- X fprintf (stderr, "How am I supposed to allocate %ld bytes?\n",
- X size),
- X exit (3);
- X free ((char *) buf);
- X if ((buf = (char *) malloc (size * sizeof (char))) == NULL)
- X fprintf (stderr, "Size too big; not enough memory.\n"),
- X exit (11);
- X break;
- X case 'a': arch = locase (optarg); break;
- X case 'd': newdir = optarg;
- X if (*newdir != '/')
- X fprintf (stderr, "Must specify full path for the directory.\n"),
- X exit (3);
- X break;
- X case 'p': password = locase (optarg); break;
- X case 'D': text = optarg; break;
- X case 'r': remove_files = TRUE; break;
- X case 'Z': no_compression = TRUE; break;
- X case 'u': updatef = TRUE; break;
- X case 'U': usage ();
- X case ':': fprintf (stderr, "Option '%c' requires an argument.\n", optopt);
- X exit (3);
- X case '?':
- X default:
- X fprintf (stderr, "Unrecognized option '%c'.\n", optopt);
- X usage ();
- X }
- X
- X if (optind == argc) {
- X fprintf (stderr, "farch: filename(s) missing.\n");
- X goto abort;
- X }
- X
- X if (!(archives_mask = getenv ("ULISTPROC_ARCHIVES_UMASK")))
- X archives_mask = "066";
- X
- X if (get_archive (&arch, fullpath, password, remove_files) &&
- X (remove_files || get_dir (newdir, &dir, fullpath))) {
- X if (remove_files)
- X rmfiles (optind, argc, argv, fullpath, no_compression, 0);
- X else {
- X if (tar)
- X if (tar_files (optind, argc, argv, tarf))
- X argc = optind + 1;
- X else
- X goto abort;
- X do_archive (optind, argc, argv, buf, fullpath, arch, dir, text, size, bin,
- X uue, split, tar, no_compression, updatef);
- X if (tar)
- X unlink (tarf);
- X }
- X }
- X abort:
- X free ((char *) dir);
- X free ((char *) buf);
- X}
- X
- X/*
- X uuencode a file.
- X*/
- X
- Xvoid uuencode (FILE **fin, char *file, char *infile, struct stat *finbuf,
- X BOOLEAN tar)
- X{
- X fclose (*fin);
- X printf ("\t- uuencoding...\n");
- X syscom ("uuencode %s %s%s > %s", file, infile, (tar ? ".tar" : ""),
- X (uue_file = mystrdup (tmpnam (NULL))));
- X *fin = fopen (uue_file, "r");
- X stat (uue_file, finbuf);
- X}
- X
- X/*
- X tar all input files into 'tarf'.
- X*/
- X
- Xint tar_files (int optind, int argc, char **argv, char *tarf)
- X{
- X FILE *fin, *fout;
- X char files[10000];
- X int original = optind;
- X
- X if ((fout = fopen (tarf, "w")) == NULL) {
- X fprintf (stderr, "Cannot write to tar file %s\n", tarf);
- X return 0;
- X }
- X fclose (fout);
- X unlink (tarf);
- X printf ("tarring...\n");
- X RESET (files);
- X while (optind < argc) {
- X if ((fin = fopen (argv[optind], "r")) == NULL) {
- X fprintf (stderr, "Unable to open %s for reading.\n", argv[optind]);
- X return 0;
- X }
- X fclose (fin);
- X sprintf (files + strlen (files), "%s ", argv[optind++]);
- X }
- X syscom ("tar -cf %s %s", tarf, files);
- X argv[original] = tarf;
- X return 1;
- X}
- X
- X/*
- X Remove the file from the archive, if found.
- X*/
- X
- Xvoid rmfiles (int optind, int argc, char **argv, char *path,
- X BOOLEAN no_compression, BOOLEAN update_dirf_only)
- X{
- X char dirf[10240];
- X char file[10240];
- X char fullpath[10240];
- X char _fullpath[10240];
- X char fullname[10240];
- X char desc[10240];
- X char *s, *tmpdir;
- X BOOLEAN continued, found, match;
- X int cnt, _cnt, i;
- X long int count;
- X FILE *fin, *fout;
- X struct stat sbuf;
- X
- X while (optind < argc) { /* Process each file */
- X
- X s = argv[optind] + strlen (argv[optind]) - 1;
- X while (s != argv[optind] && *s == '/') /* Remove trailing / */
- X *(s--) = EOS;
- X
- X i = strlen (argv[optind]);
- X if (i > 2 && argv[optind][i - 2] == '.' && argv[optind][i - 1] == 'Z')
- X argv[optind][i - 2] = EOS;
- X
- X if (!update_dirf_only)
- X printf ("%s: ", argv[optind]),
- X fflush (stdout);
- X RESET (dirf);
- X sprintf (dirf, "%s/%s", path, DIRF);
- X if (stat (dirf, &sbuf)) {
- X printf ("not removed\n");
- X fprintf (stderr, "Cannot access index %s for reading.\n", dirf);
- X exit (1);
- X }
- X signal (SIGINT, SIG_IGN);
- X syscom ("mv %s %s", dirf, (tmpdir = mystrdup (tmpnam (NULL))));
- X if ((fout = fopen (dirf, "w")) == NULL) {
- X fprintf (stderr, "Unable to open %s for writing.\nSEVERE ERROR: The \
- Xarchive is now in an inconsistent state with no DIR file.\nIts DIR file can be \
- Xfound in /tmp. Move %s to %s\n", dirf, tmpdir, dirf);
- X free ((char *) tmpdir);
- X exit (1);
- X }
- X if ((fin = fopen (tmpdir, "r")) == NULL) {
- X fprintf (stderr, "Unable to open %s for reading. Cannot proceed.\n",
- X tmpdir);
- X if (stat (dirf, &sbuf))
- X fputs ("SEVERE ERROR: The archive now has NO DIR file; DIR file \
- Xlost!!!\n", stderr);
- X else
- X fputs ("Archive intact!\n", stderr);
- X free ((char *) tmpdir);
- X exit (1);
- X }
- X RESET (fullpath);
- X found = FALSE;
- X while (!feof (fin)) { /* Get location and file-count of file */
- X file[0] = RESET (_fullpath);
- X fscanf (fin, "%s %d ", file, &_cnt);
- X match = FALSE;
- X if (file[0] != EOS) {
- X locase (file);
- X if (!strcmp (argv[optind], file))
- X match = found = TRUE;
- X if (!match)
- X fprintf (fout, "%s %d ", file, _cnt);
- X for (i = 0; i < abs (_cnt); ++i) {
- X fscanf (fin, "%ld ", &count);
- X if (!match)
- X fprintf (fout, "%ld ", count);
- X }
- X fscanf (fin, "%s", _fullpath);
- X if (!match)
- X fprintf (fout, "%s", _fullpath);
- X else
- X cnt = _cnt,
- X strcpy (fullpath, _fullpath);
- X do { /* Get file description */
- X RESET (desc);
- X fgets (desc, MAX_LINE - 2, fin);
- X if (desc [0] != EOS && desc[strlen (desc) - 1] == '\n')
- X desc[strlen (desc) - 1] = EOS;
- X continued = FALSE;
- X if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
- X desc[strlen (desc) - 1] = EOS,
- X continued = TRUE;
- X if (!match) {
- X fprintf (fout, "%s", desc);
- X if (continued)
- X fprintf (fout, "\\");
- X fputs ("\n", fout);
- X }
- X else {
- X if (!comment)
- X comment = (char *) malloc (strlen (desc) + 3),
- X *comment = EOS;
- X else
- X comment = (char *) realloc ((char *) comment, strlen (comment) +
- X strlen (desc) + 3);
- X strcat (comment, desc);
- X if (continued)
- X strcat (comment, "\\\n");
- X }
- X } while (continued);
- X }
- X }
- X if (!found)
- X printf ("not found in %s", dirf);
- X else if (!update_dirf_only) { /* Remove all parts */
- X printf ("removing parts: ");
- X fflush (stdout);
- X for (i = 1; i <= abs (cnt); i++) {
- X RESET (fullname);
- X if (abs (cnt) > 1)
- X sprintf (fullname, "%s/%s%d", fullpath, argv[optind], i);
- X else
- X sprintf (fullname, "%s/%s", fullpath, argv[optind]);
- X if (stat (fullname, &sbuf)) {
- X strcat (fullname, ".Z"); /* Check for compressed file */
- X if (no_compression || stat (fullname, &sbuf))
- X printf ("%d (not found) ", i),
- X fflush (stdout);
- X else {
- X printf ("%d ", i);
- X if (unlink (fullname))
- X printf ("(errno %d) ", errno);
- X fflush (stdout);
- X }
- X }
- X else {
- X printf ("%d ", i);
- X if (unlink (fullname))
- X printf ("(errno %d) ", errno);
- X fflush (stdout);
- X }
- X }
- X }
- X else
- X printf ("\t- updating...");
- X fclose (fin);
- X fclose (fout);
- X signal (SIGINT, SIG_DFL);
- X ++optind;
- X puts ("");
- X unlink (tmpdir);
- X }
- X free ((char *) tmpdir);
- X}
- X
- X/*
- X Check for duplicate file name and return if so. Otherwise, update the
- X archive's directory.
- X*/
- X
- Xint update (char *path, char *filename, long int count, long int *filesizes,
- X char *dir, char *text, struct stat finbuf, BOOLEAN pure_bin,
- X BOOLEAN no_compression, BOOLEAN updatef)
- X{
- X char dirf[10240];
- X char file[10240];
- X char fullpath[10240];
- X char desc[10240];
- X char stripped_file[10240];
- X char reply[80];
- X BOOLEAN continued, found = FALSE;
- X int cnt, i;
- X FILE *fout;
- X
- X strcpy (stripped_file, filename);
- X i = strlen (stripped_file);
- X if (i > 2 && stripped_file [i - 2] == '.' && stripped_file [i - 1] == 'Z')
- X stripped_file [i - 2] = EOS;
- X RESET (dirf);
- X sprintf (dirf, "%s/%s", path, DIRF);
- X if ((fout = fopen (dirf, "r")) == NULL) {
- X fprintf (stderr, "Unable to open index %s for reading.\nFile %s \
- Xnot archived. Remove output file(s) from %s\n", dirf, filename, dir);
- X exit (1);
- X }
- X while (!feof (fout)) { /* Get location and file-count of file */
- X file[0] = RESET (fullpath);
- X fscanf (fout, "%s %d %s", file, &cnt, fullpath);
- X do { /* Get file description */
- X RESET (desc);
- X fgets (desc, MAX_LINE - 2, fout);
- X if (desc [0] != EOS && desc[strlen (desc) - 1] == '\n')
- X desc[strlen (desc) - 1] = EOS;
- X continued = FALSE;
- X if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
- X desc[strlen (desc) - 1] = EOS,
- X continued = TRUE;
- X } while (continued);
- X if (file[0] != EOS) {
- X locase (file);
- X if (!strcmp (stripped_file, file)) {
- X found = TRUE;
- X break;
- X }
- X }
- X }
- X fclose (fout);
- X if (found) {
- X if (updatef)
- X rmfiles (0, 1, &filename, path, no_compression, 1);
- X else {
- X fprintf (stderr, "\t- file %s already exists in %s\n\
- X\t- file not archived\n", stripped_file, dirf);
- X remove_files (dir, filename, count, finbuf, no_compression);
- X return 0;
- X }
- X }
- X else if (updatef)
- X fprintf (stderr, "WARNING: %s is not currently archived %s\n",
- X stripped_file, dirf);
- X signal (SIGINT, SIG_IGN);
- X if ((fout = fopen (dirf, "a")) == NULL) {
- X fprintf (stderr, "Unable to open index %s for update.\nFile %s \
- Xnot archived. Exiting.\n", dirf, filename);
- X remove_files (dir, filename, count, finbuf, no_compression);
- X exit (1);
- X }
- X fprintf (fout, "%s %ld ", stripped_file, (pure_bin ? -count : count));
- X for (i = 0; i < count; i++)
- X fprintf (fout, "%ld ", filesizes[i]);
- X fprintf (fout, "%s", dir);
- X if (updatef && comment && text[0] == EOS) {
- X fprintf (fout, "%s\n", comment);
- X free ((char *) comment);
- X comment = NULL;
- X }
- X else
- X fprintf (fout, "%s%s\n", (text[0] != EOS && strcmp (text, " ") ? " " : ""),
- X (strcmp (text, " ") ? text : ""));
- X fclose (fout);
- X signal (SIGINT, SIG_DFL);
- X return 1;
- X}
- X
- X/*
- X Remove all parts of the specified file from the specified directory.
- X*/
- X
- Xvoid remove_files (char *dir, char *filename, long int count,
- X struct stat finbuf, BOOLEAN no_compression)
- X{
- X char file[10240];
- X char fout[10240];
- X struct stat foutbuf;
- X char yn;
- X BOOLEAN split = (count > 1 ? 1 : 0);
- X
- X if (!split) {
- X sprintf (fout, "%s/%s", dir, filename);
- X if (!no_compression)
- X syscom ("uncompress %s.Z > /dev/null 2>&1 < /dev/null", fout);
- X if (stat (fout, &foutbuf)) {
- X printf ("Input file %s may be the same as output file %s/%s.\n\
- XRemove %s/%s [y]? ",
- X filename, dir, filename, dir, filename);
- X fflush (stdout);
- X scanf ("%c", &yn);
- X if (yn == 'n' || yn == 'N')
- X return;
- X }
- X if ((finbuf.st_ino == foutbuf.st_ino) &&
- X (finbuf.st_dev == foutbuf.st_dev)) {
- X printf ("\t- output file matches input: not removed\n");
- X return;
- X }
- X }
- X while (count) {
- X RESET (file);
- X if (split)
- X sprintf (file, "%s/%s%d", dir, filename, count);
- X else
- X sprintf (file, "%s/%s", dir, filename);
- X unlink (file);
- X if (!no_compression)
- X strcat (file, ".Z"),
- X unlink (file);
- X --count;
- X }
- X}
- X
- Xvoid usage ()
- X{
- X fprintf (stderr, "farch {[-n] [-b | -B] [-s size] \
- X[-d dir] [-p password] [-D 'description'] [-t file] [-u]} | {<-r>} \
- X[-a archive | path-to-archive] [-Z] filename(s)\n");
- X fprintf (stderr, "-n: do not split input file(s)\n\
- X-b: input files are binary: uuencode (on if -t specified)\n\
- X-B input files are binary: do not uuencode and do not split\n\
- X-s: maximum size of each output file (in kilobytes) -- default %ld\n\
- X-d: actual directory to put output file(s)\n -- default as specified by -a: %s/<archive>\n\
- X-p: password for a new private archive\n\
- X-D: description of the file to go into the DIR file\n\
- X-t: tar all input files into 'file' and archive that\n\
- X-u: update existing files\n\
- X-a: which archive index to update (subdir of %s)\n -- \
- Xdefault %s\n\
- X-r: remove the specified file(s) from the archive\n\
- X-Z: turn off file compression\n",
- X(long) DEFAULT_SIZE / 1024, ARCHIVE_DIR, ARCHIVE_DIR, DEFAULT_ARCHIVE);
- X exit (3);
- X}
- X
- X/*
- X Archive all files given in 'argv'.
- X*/
- X
- Xvoid do_archive (int optind, int argc, char **argv, char *buf, char *fullpath,
- X char *archive, char *dir, char *text, long int size,
- X BOOLEAN bin, BOOLEAN uue, BOOLEAN split, BOOLEAN tar,
- X BOOLEAN no_compression, BOOLEAN updatef)
- X{
- X FILE *fin, *fout, *flast;
- X long int l, count, nread, nchars, total, *filesizes = NULL;
- X char *leftovers = NULL, *s, *infile = NULL, filename[10240],
- X compressed[10240];
- X struct stat sbuf, finbuf;
- X
- X while (optind < argc) { /* Split and archive each file */
- X
- X s = argv[optind] + strlen (argv[optind]) - 1;
- X while (s != argv[optind] && *s == '/') /* Remove trailing / */
- X *(s--) = EOS;
- X
- X if ((fin = fopen (argv[optind], "r")) == NULL) { /* Open file */
- X fprintf (stderr, "Cannot open file %s for reading.\n", argv[optind]);
- X goto abort;
- X }
- X
- X printf ("%s:\n", argv[optind]);
- X count = 1;
- X nchars = 0;
- X
- X if (infile) /* free previous allocation */
- X free ((char *) infile);
- X infile = extract_filename (argv[optind]); /* get filename from path */
- X locase (infile);
- X l = strlen (infile);
- X if (l > 2 && infile [l - 2] == '.' && infile [l - 1] == 'z') {
- X infile [l - 2] = EOS;
- X l = strlen (argv[optind]);
- X argv[optind][l - 2] = EOS;
- X printf ("\t- uncompressing...\n");
- X syscom ("uncompress %s > /dev/null 2>&1 < /dev/null", argv[optind]);
- X fclose (fin);
- X fin = fopen (argv[optind], "r");
- X }
- X
- X stat (argv[optind], &finbuf); /* Get size of input file */
- X if (bin && uue) /* uuencode */
- X uuencode (&fin, argv[optind], infile, &finbuf, tar);
- X
- X if (!split || finbuf.st_size <= size) { /* Not splitting;may have to copy */
- X fclose (fin);
- X sprintf (filename, "%s%s%s", (strcmp (dir, "/") ? dir : ""),
- X ((strcmp (dir, infile) && strcmp (infile, "/")) ? "/" : ""),
- X infile);
- X
- X if (updatef) /* Remove old file */
- X unlink (filename);
- X
- X if (bin) { /* Copy (possibly) uue_file to target directory */
- X if (uue && !stat (filename, &sbuf)) {
- X fprintf (stderr, "Output file %s exists; cannot proceed with %s\n",
- X filename, argv[optind]);
- X unlink (uue_file);
- X free ((char *) uue_file);
- X goto abort;
- X }
- X if (uue && (fout = fopen (filename, "w")) == NULL) { /* Test */
- X fprintf (stderr, "Cannot write to directory %s; cannot \
- Xproceed with %s\n",
- X dir, argv[optind]);
- X unlink (uue_file);
- X free ((char *) uue_file);
- X goto abort;
- X }
- X if (uue)
- X fclose (fout),
- X syscom ("mv %s %s > /dev/null 2>&1", uue_file, filename);
- X else if (stat (filename, &sbuf)) { /* File does not exist in target dir */
- X if ((fout = fopen (filename, "w")) == NULL) { /* Test */
- X fprintf (stderr, "Cannot write to directory %s; cannot \
- Xproceed with %s\n",
- X dir, argv[optind]);
- X goto abort;
- X }
- X fclose (fout);
- X syscom ("cp %s %s > /dev/null 2>&1", argv[optind], filename);
- X }
- X }
- X else if (stat (filename, &sbuf)) { /* File does not exist in target dir */
- X if ((fout = fopen (filename, "w")) == NULL) {
- X fprintf (stderr, "Cannot write to directory %s; cannot \
- Xproceed with %s\n",
- X dir, argv[optind]);
- X goto abort;
- X }
- X fclose (fout);
- X syscom ("cp %s %s > /dev/null 2>&1", argv[optind], filename);
- X }
- X else {
- X fprintf (stderr, "Output file %s exists; cannot proceed with %s\n",
- X filename, argv[optind]);
- X goto abort;
- X }
- X
- X if (!no_compression) {
- X sprintf (compressed, "%s.Z", filename);
- X if (updatef)
- X unlink (compressed);
- X else if (!stat (compressed, &sbuf)) {
- X fprintf (stderr, "Output file %s exists; cannot proceed with %s\n",
- X compressed, argv[optind]);
- X if (bin && uue)
- X unlink (uue_file),
- X free ((char *) uue_file);
- X goto abort;
- X }
- X }
- X
- X filesizes = (long int *) malloc (sizeof (long int));
- X *filesizes = (long int) finbuf.st_size;
- X if (!no_compression)
- X syscom ("compress %s > /dev/null 2>&1 < /dev/null", filename);
- X chmod (filename, 0644 & (0644 ^ otoi (archives_mask)));
- X if (update (fullpath, infile, 1, filesizes, dir, text, finbuf,bin & !uue,
- X no_compression, updatef))
- X printf ("\t- file not split, %s\n\t- archived in %s\n\t- directory: %s\n",
- X (no_compression ? "not compressed" : "compressed"),
- X archive, dir);
- X free ((long int *) filesizes);
- X filesizes = NULL;
- X }
- X else { /* Split file */
- X while (!feof (fin)) {
- X sprintf (filename, "%s%s%s%d", (strcmp (dir, "/") ? dir : ""),
- X ((strcmp (dir, infile) && strcmp (infile, "/")) ? "/" : ""),
- X infile, count);
- X
- X if (updatef)
- X unlink (filename);
- X else if (!stat (filename, &sbuf)) {
- X fprintf (stderr, "Output file %s exists; cannot proceed with %s\n",
- X filename, argv[optind]);
- X if (bin)
- X unlink (uue_file),
- X free ((char *) uue_file);
- X fout = (FILE *) -1;
- X break;
- X }
- X if ((fout = fopen (filename, "w")) == NULL) {
- X fprintf (stderr, "Cannot write to directory %s; cannot proceed \
- Xwith %s\n",
- X dir, argv[optind]);
- X fout = (FILE *) -1;
- X break;
- X }
- X chmod (filename, 0644 & (0644 ^ otoi (archives_mask)));
- X
- X total = 0; /* Do the actual splitting */
- X total += fwrite (leftovers, sizeof (char), nchars, fout);
- X nread = fread (buf, sizeof (char), size - nchars, fin);
- X if (nchars)
- X free ((char *) leftovers);
- X s = buf + nread - (nread > 0 ? 1 : 0);
- X nchars = 0;
- X while (s != buf && *s != '\n') /* Look for first \n from the end */
- X ++nchars,
- X --s;
- X if (s == buf) /* No new line found; write as is */
- X nchars = 0;
- X nread -= nchars;
- X leftovers = (char *) malloc (nchars * sizeof (char));
- X strncpy (leftovers, ++s, nchars); /* Copy anything after \n */
- X total += fwrite (buf, sizeof (char), nread, fout);
- X fclose (fout);
- X
- X if (total == 0)
- X unlink (filename);
- X else { /* OK, compress */
- X if (!no_compression) {
- X sprintf (compressed, "%s.Z", filename);
- X if (updatef)
- X unlink (compressed);
- X else if (!stat (compressed, &sbuf)) {
- X fprintf (stderr, "Output file %s exists; cannot proceed with %s\n",
- X compressed, argv[optind]);
- X if (bin)
- X unlink (uue_file),
- X free ((char *) uue_file);
- X unlink (filename);
- X goto abort;
- X }
- X }
- X stat (filename, &sbuf);
- X filesizes = (long int *)
- X (filesizes ?
- X (realloc ((long int *) filesizes, count * sizeof (long int))) :
- X (malloc (count * sizeof (long int))));
- X *(filesizes + (count - 1)) = (long int) sbuf.st_size;
- X if (!no_compression)
- X syscom ("compress %s > /dev/null 2>&1 < /dev/null", filename);
- X ++count; /* Always one ahead */
- X }
- X }
- X
- X fclose (fin);
- X if (bin)
- X unlink (uue_file),
- X free ((char *) uue_file);
- X if (nchars) /* write any leftovers */
- X flast = fopen (filename, "a"),
- X fwrite (leftovers, sizeof (char), nchars, flast),
- X fclose (flast),
- X free ((char *) leftovers),
- X stat (filename, &sbuf),
- X *(filesizes + (count - 2)) = (long int) sbuf.st_size;
- X
- X if (fout != (FILE *) -1) { /* Splitting successful, update DIR file */
- X if (update (fullpath, infile, count - 1, filesizes, dir, text, finbuf,
- X bin & !uue, no_compression, updatef))
- X printf ("\t- file split in %ld %scompressed parts\n\t- archived in %s\n\t\
- X- directory: %s\n",
- X (long) count - 1,
- X (no_compression ? "un" : ""),
- X archive, dir);
- X free ((long int *) filesizes);
- X filesizes = NULL;
- X }
- X }
- X abort:
- X ++optind;
- X }
- X}
- X
- X/*
- X Get archive to update.
- X*/
- X
- Xint get_archive (char **archive, char *fullpath, char *password,
- X BOOLEAN remove_file)
- X{
- X FILE *master;
- X char indexf[10240], line[10240], cur_archive[10240], arch[10240], dirf[10240],
- X error [10240], *slash;
- X char original[10240];
- X BOOLEAN found = FALSE;
- X
- X if (!*archive)
- X *archive = DEFAULT_ARCHIVE;
- X strcpy (cur_archive, (char *) *archive);
- X strcpy (original, *archive);
- X if ((slash = strchr (cur_archive, '/')))
- X *slash = EOS;
- X sprintf (indexf, "%s/%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE, INDEX);
- X while (*archive[0] != EOS) { /* Check all archives specified */
- X if ((master = fopen (indexf, "r")) == NULL) {
- X fprintf (stderr, "Sorry, no master index found.\n");
- X return 0;
- X }
- X found = FALSE;
- X while (!feof (master)) { /* Look at the current index for fullpath */
- X indexf[0] = arch[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, master);
- X if (line[0] != EOS) {
- X sscanf (line, "%s %s\n", arch, indexf);
- X locase (arch);
- X if (!strcmp (arch, cur_archive)) {
- X found = TRUE;
- X break;
- X }
- X }
- X }
- X fclose (master);
- X if (!found && remove_file) {
- X fprintf (stderr, "%s: not a valid archive or path.\n", cur_archive);
- X return 0;
- X }
- X sprintf (dirf, "%s/%s/%s", ARCHIVE_DIR, original, DIRF);
- X if (!found) {
- X sprintf (dirf, "%s/%s/%s", ARCHIVE_DIR, original, DIRF);
- X printf ("New archive %s; creating all directories and necessary files\n",
- X original);
- X if (!make_indexes (dirf, original, password, error, "077")) {
- X fprintf (stderr, "%s", error);
- X return 0;
- X }
- X sprintf (indexf, "%s/%s", ARCHIVE_DIR, original);
- X }
- X if ((slash = strchr (*archive, '/')))
- X sprintf (*archive, "%s", slash + 1); /* Move down the path */
- X else
- X sprintf (*archive, "%s", *archive + strlen (cur_archive));
- X strcpy (cur_archive, *archive);
- X if ((slash = strchr (cur_archive, '/')))
- X *slash = EOS;
- X if (cur_archive[0] != EOS)
- X sprintf (indexf, "%s/%s", indexf, INDEX);
- X }
- X strcpy (fullpath, indexf);
- X strcpy (*archive, original);
- X return 1;
- X}
- X
- X/*
- X Get output directory.
- X*/
- X
- Xint get_dir (char *newdir, char **dir, char *fullpath)
- X{
- X char *s;
- X char msg [MAX_LINE];
- X struct stat sbuf;
- X
- X free ((char *) *dir);
- X if (!newdir)
- X *dir = (char *) malloc ((strlen (fullpath) + 1) * sizeof (char)),
- X sprintf (*dir, "%s", fullpath);
- X else {
- X *dir = (char *) malloc ((strlen (newdir) + 1) * sizeof (char));
- X sprintf (*dir, "%s", newdir);
- X s = *dir + strlen (*dir) - 1;
- X while (s != *dir && *s == '/')
- X *(s--) = EOS;
- X }
- X if (stat (*dir, &sbuf)) {
- X if (!mkdir1 (*dir, msg, "077")) {
- X fprintf (stderr, "Unable to create new directory %s\n%s", *dir, msg);
- X return 0;
- X }
- X printf ("Creating new directory %s\n", *dir);
- X }
- X return 1;
- X}
- X
- X/*
- X Required to avoid undefined symbols.
- X*/
- X
- Xint gexit (int exitcode)
- X{
- X exit (exitcode);
- X}
- *-*-END-of-src/farch.c-*-*
- echo x - src/fio.c
- sed 's/^X//' >src/fio.c <<'*-*-END-of-src/fio.c-*-*'
- X#include <stdio.h>
- X#include <string.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <sys/file.h>
- X#include <fcntl.h>
- X#include <errno.h>
- X# ifdef unknown_port
- Xextern int errno;
- X# endif
- X#if !defined (stellar) && !defined (unknown_port)
- X# include <time.h>
- X#endif
- X#include <sys/time.h>
- X#if !defined (__NeXT__) && !defined (stardent) && !defined (unknown_port)
- X# include <utime.h> /* not in NeXT OS 2.1; Under 3.0, included by sys/types.h */
- X#else
- X# include "next.h"
- X#endif
- X#include "defs.h"
- X
- X/*
- X Speed up the system by not forking off processes for things that
- X can be done with a syscall or two (or 50 for that matter).
- X
- X Copyright 1993
- X Kenneth Lorber (keni@oasys.dt.navy.mil)
- X David Taylor Model Basin
- X Carderock Division, Naval Surface Warfare Center
- X
- X This code may be freely redistributed.
- X
- X [tasos: the code has been expanded to use the ULISTPROC_UMASK environment
- X variable, fixed spacing to match the rest of the system and some function
- X prototyping problems; also altered syntax/use of utime() for NeXT hosts,
- X and removed const declarations which are not removed by the unproto package,
- X plus some bug fixing as well]
- X*/
- X
- X#ifdef __STDC__
- X# include <stdarg.h>
- Xchar *tsprintf (char *, ...);
- X#else
- X# include <varargs.h>
- Xchar *tsprintf ();
- X#endif
- X
- Xextern char *extract_filename (char *);
- Xextern void shrink (char *);
- Xextern int otoi (char *);
- Xextern char *getenv ();
- X
- Xtypedef enum append { NOAPPEND, APPEND } _append;
- Xstatic int echo_internal (char *, char *, _append);
- Xstatic int cat_internal (char *, char *, _append);
- Xstatic int log_warn (char *);
- X
- Xint echo (char *, char *);
- Xint echo_append (char *, char *);
- Xint mv (char *, char *);
- Xint cp (char *, char *);
- Xint cat (char *, char *);
- Xint cat_append (char *, char *);
- Xint touch (char *);
- X
- Xint echo (char *text, char *file)
- X{
- X return echo_internal (text, file, NOAPPEND);
- X}
- X
- Xint echo_append (char *text, char *file)
- X{
- X return echo_internal (text, file, APPEND);
- X}
- X
- Xstatic int echo_internal (char *text, char *file, _append append)
- X{
- X int d;
- X long int len;
- X char *mask;
- X
- X if ((mask = getenv ("ULISTPROC_UMASK")))
- X umask (otoi (mask));
- X else
- X mask = "066",
- X umask (S_IRWXG|S_IRWXO); /* 600 */
- X if (append == APPEND)
- X d = open (file, O_CREAT|O_APPEND|O_WRONLY, 0666 & (0666 ^ otoi (mask)));
- X else
- X d = open (file, O_CREAT|O_TRUNC|O_WRONLY, 0666 & (0666 ^ otoi (mask)));
- X if (d == -1) {
- X log_warn (tsprintf ("echo: open: %s", file));
- X return 1;
- X }
- X
- X len = strlen (text);
- X if (len != write (d, text, len))
- X goto write_error;
- X if (1 != write (d, "\n", 1)) {
- X write_error:
- X log_warn (tsprintf ("echo: write: %s", file));
- X close (d);
- X return 1;
- X }
- X
- X if (close (d)) {
- X log_warn (tsprintf ("echo: close: %s", file));
- X return 1;
- X }
- X return 0;
- X}
- X
- Xint mv (char *oldfile, char *newfile)
- X{
- X (void) unlink (newfile);
- X errno = 0;
- X if (link (oldfile, newfile)) {
- X if (errno == EXDEV) {
- X if (cp (oldfile, newfile))
- X return 1; /* can't copy either */
- X }
- X else {
- X log_warn (tsprintf ("mv: %s %s", oldfile, newfile));
- X return 0;
- X }
- X }
- X unlink (oldfile);
- X return 0;
- X}
- X
- Xint cp (char *oldfile, char *newfile)
- X{
- X struct stat oldstat, newstat;
- X int oldfd, newfd;
- X char *newname, *buffer, *mask, buf[256];
- X long int size;
- X
- X if ((mask = getenv ("ULISTPROC_UMASK")))
- X umask (otoi (mask));
- X else
- X mask = "066",
- X umask (S_IRWXG|S_IRWXO); /* 600 */
- X oldfd = open (oldfile, O_RDONLY, 0);
- X if (oldfd < 0) {
- X log_warn (tsprintf ("cp: open: %s", oldfile));
- X return 1;
- X }
- X if (fstat (oldfd, &oldstat)) {
- X log_warn (tsprintf ("cp: fstat: %s", oldfile));
- X close (oldfd);
- X return 1;
- X }
- X
- X newname = newfile;
- X if (!stat (newfile, &newstat)) {
- X if (newstat.st_mode & S_IFDIR) {
- X char *s;
- X sprintf (buf, "%s/%s", newfile, (s = extract_filename (oldfile)));
- X newname = buf;
- X free ((char *) s);
- X }
- X }
- X
- X newfd = open (newname, O_WRONLY|O_TRUNC|O_CREAT,
- X oldstat.st_mode & (0666 ^ otoi (mask)));
- X if (newfd < 0) {
- X log_warn (tsprintf ("cp: open: %s", newname));
- X close (oldfd);
- X return 1;
- X }
- X
- X buffer = (char *) malloc (65536 * sizeof (char));
- X while ((size = read (oldfd, buffer, 65536)) > 0) {
- X if (size != write (newfd, buffer, size)) {
- X log_warn (tsprintf ("cp: write %s", newname));
- X free ((char *) buffer);
- X close (oldfd);
- X close (newfd);
- X return 1;
- X }
- X }
- X free ((char *) buffer);
- X if (size < 0) {
- X log_warn (tsprintf ("cp: read: %s", oldfile));
- X close (oldfd);
- X close (newfd);
- X return 1;
- X }
- X close (oldfd);
- X close (newfd);
- X return 0;
- X}
- X
- Xint cat (char *srcfile, char *dstfile)
- X{
- X return cat_internal (srcfile, dstfile, NOAPPEND);
- X}
- X
- Xint cat_append (char *srcfile, char *dstfile)
- X{
- X return cat_internal (srcfile, dstfile, APPEND);
- X}
- X
- Xstatic int cat_internal (char *srcfile, char *dstfile, _append append)
- X{
- X struct stat srcstat;
- X int srcfd, dstfd;
- X char *buffer, *mask;
- X long int size;
- X
- X if ((mask = getenv ("ULISTPROC_UMASK")))
- X umask (otoi (mask));
- X else
- X mask = "066",
- X umask (S_IRWXG|S_IRWXO); /* 600 */
- X srcfd = open (srcfile, O_RDONLY, 0);
- X if (srcfd < 0) {
- X log_warn (tsprintf ("cat: open: %s", srcfile));
- X return 1;
- X }
- X if (fstat (srcfd, &srcstat)) {
- X log_warn (tsprintf ("cat: fstat: %s", srcfile));
- X close (srcfd);
- X return 1;
- X }
- X
- X if (append == APPEND)
- X dstfd = open (dstfile, O_WRONLY|O_APPEND|O_CREAT,
- X srcstat.st_mode & (0666 ^ otoi (mask)));
- X else
- X dstfd = open (dstfile, O_WRONLY|O_TRUNC|O_CREAT,
- X srcstat.st_mode & (0666 ^ otoi (mask)));
- X if (dstfd < 0) {
- X log_warn (tsprintf ("cat: open: %s", dstfile));
- X close (srcfd);
- X return 1;
- X }
- X
- X buffer = (char *) malloc (65536 * sizeof (char));
- X while ((size = read (srcfd, buffer, 65536)) > 0) {
- X if (size != write (dstfd, buffer, size)) {
- X log_warn (tsprintf ("cat: write: %s", dstfile));
- X free ((char *) buffer);
- X close (srcfd);
- X close (dstfd);
- X return 1;
- X }
- X }
- X free ((char *) buffer);
- X if (size < 0) {
- X log_warn (tsprintf ("cat: read: %s", srcfile));
- X close (srcfd);
- X close (dstfd);
- X return 1;
- X }
- X close (srcfd);
- X close (dstfd);
- X return 0;
- X}
- X
- Xint touch (char *file)
- X{
- X char *mask;
- X int d;
- X#ifdef __NeXT__
- X struct timeval tvp[2];
- X#elif defined (i386)
- X struct utimbuf utimest;
- X#endif
- X
- X if ((mask = getenv ("ULISTPROC_UMASK")))
- X umask (otoi (mask));
- X else
- X mask = "066",
- X umask (S_IRWXG|S_IRWXO); /* 600 */
- X d = open (file, O_CREAT|O_EXCL, 0666 & (0666 ^ otoi (mask)));
- X#ifdef __NeXT__
- X tvp[0].tv_sec = tvp[0].tv_usec = tvp[1].tv_sec = tvp[1].tv_usec = 0;
- X#elif defined (i386)
- X utimest.actime = utimest.modtime = 0;
- X#endif
- X
- X if (d < 0) {
- X if (errno != EEXIST) {
- X log_warn (tsprintf ("touch: open: %s", file));
- X return 1;
- X }
- X }
- X else {
- X close (d);
- X return 0;
- X }
- X#ifdef __NeXT__
- X if (utime (file, tvp)) {
- X#elif defined (i386) || defined (linux)
- X if (utime (file, &utimest)) {
- X#else
- X if (utime (file, NULL)) {
- X#endif
- X log_warn (tsprintf ("touch: utime: %s",file));
- X return 1;
- X }
- X return 0;
- X}
- X
- X/* support routines */
- X
- X#ifdef __STDC__
- Xchar *tsprintf (char *control, ...)
- X#else
- Xchar *tsprintf (control, va_alist)
- Xchar *control;
- Xva_dcl
- X#endif
- X{
- X static char command [10240];
- X va_list ap;
- X
- X#ifdef __STDC__
- X va_start (ap, control);
- X#else
- X va_start (ap);
- X#endif
- X RESET (command);
- X vsprintf (command, control, ap);
- X va_end (ap);
- X return command;
- X}
- X
- Xstatic int log_warn (char *command)
- X{
- X extern BOOLEAN tty_echo;
- X FILE *f;
- X struct tm *t;
- X#ifdef ultrix
- X time_t time_is = 0;
- X#else
- X long int time_is = 0;
- X#endif
- X int _errno = errno;
- X
- X if ((f = fopen (WARNING, "a")) != NULL)
- X fprintf (f, "\nWARNING: System call errno %d: %s\n", _errno, command),
- X time (&time_is),
- X t = localtime (&time_is),
- X fprintf (f, "Time/Date: %2d:%.2d:%.2d, %2d/%.2d/%2d\n",
- X t->tm_hour, t->tm_min, t->tm_sec, t->tm_mon + 1, t->tm_mday,
- X t->tm_year),
- X fclose (f);
- X if (tty_echo)
- X printf ("\nWARNING: System call errno %d: %s\n", _errno, command);
- X}
- *-*-END-of-src/fio.c-*-*
- echo x - src/fwin.c
- sed 's/^X//' >src/fwin.c <<'*-*-END-of-src/fwin.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | FILE WINDOW |
- X | |
- X | Version 1.0 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X Copy a window of the input (stdin) to output (stdout); the window is defined
- X as an offset from the beginning and a byte count. If no byte count is defined
- X then MAXINT is used.
- X
- X COMMAND LINE OPTIONS:
- X -o: Set the offset from the beginning of the file (default 0).
- X -b: Set the byte count (default MAXINT).
- X -n: Pad with new line at the end if not there.
- X*/
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#if !defined (__NeXT__) && !defined (NetBSD)
- X# ifndef unknown_port
- X# include <unistd.h>
- X# endif
- X# if !defined (sequent) && !defined (__convex__) && !defined (apollo) && \
- X !defined (unknown_port)
- X# include <values.h>
- X# endif
- X#else
- X# include <libc.h>
- X#endif
- X
- X#ifndef __NeXT__
- Xextern long int atol (char *);
- X#else
- Xextern long int atol (const char *);
- X#endif
- X
- X#define BUFFSIZ 8192
- X#ifndef MAXINT
- X# define MAXINT 0x7FFFFFFF /* assumes 32-bit hardware */
- X#endif
- X
- Xmain (int argc, char **argv)
- X{
- X char *options = "o:b:n", last_byte;
- X long int offset = 0, bytes = MAXINT, bytes_read = 0, total_bytes = 0;
- X int pad_with_newline = 0, c;
- X char buf [BUFFSIZ];
- X extern char *optarg;
- X
- X while ((c = getopt (argc, argv, options)) != EOF)
- X switch ((char) c) {
- X case 'o':
- X if ((offset = atol (optarg)) < 0)
- X fprintf (stderr, "Negative offset (%ld) not allowed.\n", offset),
- X exit (3);
- X break;
- X case 'b':
- X if ((bytes = atol (optarg)) < 0)
- X fprintf (stderr, "Negative number of bytes to output (%ld) not allowed.\n", bytes),
- X exit (3);
- X break;
- X case 'n': pad_with_newline = 1; break;
- X default:
- X printf ("Usage: %s [-n] [-o offset] [-b bytes]\n", argv[0]);
- X exit (3);
- X }
- X
- X /* Skip to offset */
- X while ((bytes_read = read (fileno (stdin), buf, BUFFSIZ)) > 0) {
- X total_bytes += bytes_read;
- X if (total_bytes >= offset)
- X break;
- X }
- X if (total_bytes >= offset && bytes_read > 0) {
- X last_byte =
- X buf[bytes_read - total_bytes + offset +
- X (total_bytes - offset <= bytes ? total_bytes - offset : bytes) - 1];
- X total_bytes =
- X write (fileno (stdout),
- X &buf[bytes_read - total_bytes + offset],
- X (total_bytes - offset <= bytes ? total_bytes - offset : bytes));
- X if (total_bytes < bytes)
- X while ((bytes_read = read (fileno (stdin), buf, BUFFSIZ)) > 0) {
- X total_bytes += bytes_read;
- X write (fileno (stdout), buf,
- X (total_bytes <= bytes ?
- X bytes_read :
- X bytes_read - total_bytes + bytes));
- X last_byte = buf [(total_bytes <= bytes ? bytes_read :
- X bytes_read - total_bytes + bytes) - 1];
- X if (total_bytes >= bytes)
- X break;
- X }
- X }
- X if (pad_with_newline && last_byte != '\n')
- X write (fileno (stdout), "\n", 1);
- X fclose (stdout);
- X if (bytes_read > 0)
- X while (read (fileno (stdin), buf, BUFFSIZ) > 0);
- X exit (0);
- X}
- *-*-END-of-src/fwin.c-*-*
- echo x - src/ilp.c
- sed 's/^X//' >src/ilp.c <<'*-*-END-of-src/ilp.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | INTERACTIVE LISTPROCESSOR CLIENT |
- X | |
- X | Version 2.1 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X This program is to be used for connecting to an interactive ListProcessor
- X server (version 6.0 and up). The following files are required:
- X
- X ilp.c (this file)
- X ilp.h
- X ilpp.h (definition of the Interactive ListProcessor Protocol)
- X makefile
- X
- X Usage: ilp [-v] [-t timeout] [-b buffer-size in K] <host> [port]
- X
- X To connect to a host you may specify its name or IP address. The default
- X port is 372; another port may be specified as an extra argument. To echo
- X server responses to client requests, use the -v flag.
- X
- X The default time out for a server response is 180 seconds; to reset
- X use the -t flag. The default socket buffer size is 8K; to reset use
- X the -b flag (the argument specifies kilobytes).
- X
- X This client is to be used as a model and better ones can certainly be
- X written.
- X
- X SCO system should compile with -Dsco.
- X
- X Refer to the man page for more information on how to use this program.
- X
- X Compile with -DNO_ABORT_OP if compiler errors are generated.
- X
- X Version history:
- X 1.0: original version -- no abort operation
- X 2.0: abort operation implemented -- requires server support also, versions
- X 6.0a (July 1 1993) or later; better shell control
- X 2.1: reduced CPU usage
- X*/
- X
- X#include <signal.h>
- X#include "defs.h"
- X#undef NSIG
- X#ifdef GO_INTERACTIVE
- X# include <stdio.h>
- X# include <sys/types.h>
- X# include <string.h>
- X# if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
- X && !defined (sequent) && !defined (unknown_port)
- X# include <malloc.h>
- X# endif
- X# ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X# endif
- X# if defined (stardent) || defined (stellar) || defined (titan)
- X# include <rpc/types.h>
- X# endif
- X# include <sys/stat.h>
- X# include <fcntl.h>
- X# include <errno.h>
- X# ifdef unknown_port
- Xextern int errno;
- X# endif
- X# include <sys/socket.h>
- X# include <netinet/in.h>
- X# include <netdb.h>
- X# include <sys/file.h>
- X# include <sys/ioctl.h>
- X# if defined (sco) || defined (M_XENIX) || defined (M_UNIX)
- X# include <sys/stropts.h>
- X# endif
- X# ifndef NO_ABORT_OP
- X# if defined (sgi) || defined (__sgi)
- X# include <net/soioctl.h>
- X# elif !defined (hpux) && !defined (__hpux) && !defined (ultrix) && \
- X !defined (mips) && !defined (__mips) && !defined (titan) && \
- X !defined (__DGUX__) && !defined (stellar) && !defined (_AIX) && \
- X !defined (i386) && !defined (__NeXT__) && !defined (__convex__) && \
- X !defined (titan) && !defined (M_UNIX) && !defined (M_XENIX) && \
- X !defined (xenix) && !defined (sco) && !defined (apollo) && \
- X !defined (__osf__) && !defined (sequent)
- X# include <sys/sockio.h>
- X# endif
- X# endif
- X# if (defined (sco) || defined (M_XENIX) || defined (M_UNIX)) && \
- X defined (HAVE_SELECT_H)
- X# include <sys/times.h>
- X# else
- X# include <sys/time.h>
- X# endif
- X# ifdef HAVE_SELECT_H
- X# include <sys/select.h>
- X# endif
- X# ifdef HAVE_ULIMIT_H
- X# include <ulimit.h>
- X# endif
- X# include "ilp.h"
- X
- X# ifndef UL_GDESLIM
- X# define UL_GDESLIM 4
- X# endif
- X# ifndef FD_SET /* for 4.2BSD */
- X# define FD_SETSIZE (sizeof(fd_set) * 8)
- X# define FD_SET(n, p) (((fd_set *) (p))->fds_bits[0] |= (1 << ((n) % 32)))
- X# define FD_CLR(n, p) (((fd_set *) (p))->fds_bits[0] &= ~(1 << ((n) % 32)))
- X# define FD_ISSET(n, p) (((fd_set *) (p))->fds_bits[0] & (1 << ((n) % 32)))
- X# define FD_ZERO(p) memset ((char *)(p), '\0', sizeof(*(p)))
- X# endif
- X
- X# ifndef __NeXT__
- Xextern long int atoi (char *);
- X# else
- Xextern int atoi (const char *);
- X# endif
- Xextern int optind;
- X# if !defined (hpux) && !defined (__hpux)
- Xextern int getopt (int, char **, char *);
- X# endif
- X
- Xint main (int, char **);
- Xint server_response (int);
- Xint build_tcp_connection (char *, int);
- Xint sighandle (int);
- Xint urg_data (int);
- Xint alarm_clock (int);
- Xlong int read_from_fd (int, long int, FILE *);
- Xlong int write_to_fd (int, char *, long int);
- Xint open_file (char *, int, int);
- Xint check_server_response (int, char *);
- Xint check_for_redirection (char *, char *);
- XFILE *check_for_pipe (char *);
- Xint prevch (char *, char *);
- Xint nextch (char *);
- X
- Xlong int nbytes, sock_fd, buffsiz = BUFFSIZ;
- Xint to_file, prompt_len, verbose, check_sio, response_timeout = TIMEOUT,
- X fd = -1, broken_pipe = 0, sigint = 1, interrupted = 0, cmd, no_abort_op = 0,
- X pliteral, nliteral, literal, timed_out;
- X
- Xchar args [256];
- XFILE *pipefp = NULL;
- X#endif
- X
- X/*
- X Main function. Connect to server, issue requests and receive replies.
- X
- X Returns: 0 on success, 1 on command line option error, or an ILPP
- X command if the transaction was terminated normally.
- X*/
- X
- Xmain (int argc, char **argv)
- X{
- X#ifndef GO_INTERACTIVE
- X printf ("%s not functional. Try compiling archives/ilp/ilp.c\n", argv[0]);
- X#else
- X char *options = "vt:b:";
- X char *buf, *tmp, infile [256], wbuf [256], version [80];
- X int i, port, timeout, sprompt_len, c, rfd, bytes_alloced = 0, rtc = TIMEOUT;
- X struct stat stat_buf;
- X extern char *optarg;
- X
- X port = PORT;
- X while ((c = getopt (argc, argv, options)) != EOF)
- X switch ((char) c) {
- X case 'v': verbose = 1; break;
- X case 't':
- X if ((response_timeout = atoi (optarg)) < 1) {
- X printf ("-t %d\nBe real.\n", response_timeout);
- X return 1;
- X }
- X rtc = response_timeout;
- X break;
- X case 'b':
- X if ((buffsiz = atol (optarg) * 1024) < 1024) {
- X printf ("-b %ld\nBe real.\n", buffsiz);
- X return 1;
- X }
- X break;
- X case '?':
- X default:
- X fprintf (stderr, "Usage: %s [-v] [-t timeout] [-b buffer-size in K] \
- X<host> [port]\n", argv[0]);
- X return 1;
- X }
- X
- X if (optind == argc) {
- X fprintf (stderr, "Usage: %s [-v] [-t timeout] [-b buffer-size in K] \
- X<host> [port]\n", argv[0]);
- X return 1;
- X }
- X else if (optind + 1 < argc)
- X port = atoi (argv [optind + 1]);
- X# ifdef SIGIO
- X signal (SIGIO, (void (*)()) urg_data);
- X# endif
- X# ifdef SIGURG
- X signal (SIGURG, (void (*)()) urg_data);
- X# endif
- X if ((sock_fd = build_tcp_connection (argv[optind], port)) < 0)
- X return SYS_ERROR;
- X if ((cmd = server_response (sock_fd)) != CONNECT) {
- X PRINTF (cmd, "Handshake failed\n");
- X printf ("Not an interactive ListProcessor.\n");
- X return cmd;
- X }
- X
- X for (i = SIGHUP; i <= SIGPIPE; i++)
- X signal (i, (void (*)()) sighandle);
- X signal (SIGALRM, (void (*)()) alarm_clock);
- X
- X if (check_server_response (cmd, args)) goto abort;
- X timeout = nbytes;
- X sscanf (args, "%s %d %d\n", version, &prompt_len, &sprompt_len);
- X
- X if ((cmd = server_response (sock_fd)) < 0) goto abort; /* Get greeting */
- X check_server_response (cmd, args);
- X if (cmd != CONN_CLOSED && cmd != SERVER_BUSY && cmd != PEER_UNAVAIL &&
- X cmd != CONN_ABORTED && cmd != SYS_ERROR && cmd != CONN_TIMEOUT)
- X printf ("\nHit ^\\ (control-backslash) to abort at any time.\n");
- X if (!strcmp (version, "6.0"))
- X no_abort_op = 1,
- X printf ("WARNING: Server does not support the ^C abort operation.\n\
- XWARNING: Server uses another protocol for the append operation >>\n");
- X if (read_from_fd (sock_fd, nbytes, NULL) < 0) goto abort;
- X if (cmd == CONN_CLOSED || cmd == SERVER_BUSY || cmd == PEER_UNAVAIL ||
- X cmd == CONN_ABORTED || cmd == SYS_ERROR || cmd == CONN_TIMEOUT)
- X goto abort;
- X bytes_alloced = 256;
- X if ((buf = (char *) malloc (bytes_alloced * sizeof (char))) == NULL) {
- X printf ("FATAL: malloc() failed\n");
- X goto abort;
- X }
- X check_sio = 1;
- X fgets (buf, bytes_alloced - 1, stdin); /* Put email address */
- X if (strlen (buf) == 0)
- X printf ("\n"),
- X strcpy (buf, "\n");
- X check_sio = 0;
- X if (write_to_fd (sock_fd, buf, strlen (buf)) < 0) goto abort;
- X if ((cmd = server_response (sock_fd)) < 0) /* See if "Password: " follows */
- X goto abort;
- X if (check_server_response (cmd, args)) goto abort;
- X if (cmd == PASSWORD_REQUIRED) {
- X RESET (buf);
- X check_sio = 1;
- X fgets (buf, 255, stdin);
- X if (strlen (buf) == 0)
- X printf ("\n"),
- X strcpy (buf, "\n");
- X check_sio = 0;
- X if (write_to_fd (sock_fd, buf, strlen (buf)) < 0)
- X goto abort;
- X }
- X if (cmd == PEER_UNAVAIL) {
- X read_from_fd (sock_fd, nbytes, NULL);
- X goto abort;
- X }
- X
- X memset (buf, EOS, bytes_alloced);
- X sigint = 0;
- X while (cmd != CONN_CLOSED && cmd != CONN_ABORTED && cmd != CONN_TIMEOUT) {
- X signal (SIGINT, (void (*)()) sighandle);
- X interrupted = 0;
- X if ((cmd = server_response (sock_fd)) < 0) break;
- X if (check_server_response (cmd, args)) break;
- X if (cmd == TEST_FILE_PERMISSIONS) continue;
- X interrupted = 0;
- X if (cmd != CONN_ABORTED && cmd != CONN_TIMEOUT)
- X if (read_from_fd (sock_fd, nbytes, (cmd != MESSAGE ? pipefp : NULL)) < 0)
- X break;
- X signal (SIGINT, SIG_IGN);
- X broken_pipe = 0;
- X if (cmd == MESSAGE) {
- X response_timeout -= 10;
- X if (response_timeout <= 0)
- X response_timeout = 1;
- X continue;
- X }
- X if (cmd != CONN_CLOSED && cmd != CONN_ABORTED && cmd != CONN_TIMEOUT) {
- X response_timeout = rtc;
- X check_sio = 1;
- X if (pipefp)
- X strcpy (buf, "\n");
- X if (buf [0] == EOS) {
- X RESET (infile);
- X if (!fgets (buf, bytes_alloced - 1, stdin))
- X strcpy (buf, "exit\n");
- X if (strlen (buf) == 0) /* EOF */
- X printf ("\n"),
- X strcpy (buf, "\n");
- X if ((rfd = check_for_redirection (buf, infile)) < 0)
- X strcpy (buf, "\n");
- X if (rfd >= 0 && infile [0] != EOS) { /* Input redirection */
- X fstat (rfd, &stat_buf);
- X if (!(stat_buf.st_mode & S_IFREG)) {
- X printf ("%s: Not a regular file\n", infile);
- X strcpy (buf, "\n");
- X goto skip;
- X }
- X if (stat_buf.st_size + strlen (buf) + 2 > bytes_alloced) {
- X bytes_alloced = stat_buf.st_size + strlen (buf) + 2;
- X if ((buf = (char *) realloc (buf, bytes_alloced * sizeof (char))) ==
- X NULL) {
- X printf ("FATAL: realloc() failed\n");
- X break;
- X }
- X }
- X i = strlen (buf);
- X if (read (rfd, &buf [strlen (buf)], stat_buf.st_size) <
- X stat_buf.st_size) {
- X printf ("FATAL: Failed to read all of the input file\n");
- X break;
- X }
- X buf [i + stat_buf.st_size] = EOS;
- X if (buf [i + stat_buf.st_size - 1] != '\n')
- X strcat (&buf [i + stat_buf.st_size], "\n");
- X close (rfd);
- X }
- X }
- X skip:
- X strncpy (wbuf, buf, 254);
- X tmp = strchr (wbuf, '\n');
- X if (!tmp)
- X wbuf [254] = '\n',
- X wbuf [255] = EOS;
- X else
- X *(tmp + 1) = EOS;
- X if (pipefp)
- X pclose (pipefp);
- X check_sio = 0;
- X pipefp = check_for_pipe (wbuf);
- X if (write_to_fd (sock_fd, wbuf, strlen (wbuf)) < 0) break;
- X sprintf (buf, "%s", strchr (buf, '\n') + 1);
- X }
- X }
- X
- X abort:
- X if (pipefp)
- X pclose (pipefp);
- X close (sock_fd);
- X printf ("Connection closed.\n");
- X if (buf)
- X free ((char *) buf);
- X if (cmd == CONN_CLOSED)
- X return 0;
- X return cmd;
- X#endif
- X}
- X
- X#ifdef GO_INTERACTIVE
- X/*
- X Get server response. Store in 'nbytes' the number of bytes in the actual
- X message that follows, and in 'args' the (optional) file name.
- X
- X Returns: the server reply code, CONN_TIMEOUT, CONN_ABORTED, or -1 on
- X protocol errors.
- X*/
- X
- Xint server_response (int sock_fd)
- X{
- X char buf [256];
- X int cmd = -1, i, bytes_to_read = 4, bytes_read = 0, value, nfds;
- X fd_set rfds;
- X struct timeval timeout;
- X
- X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
- X defined (apollo) || defined (unknown_port)
- X nfds = getdtablesize ();
- X# else
- X nfds = ulimit (UL_GDESLIM);
- X# endif
- X memset (buf, EOS, 256);
- X while (bytes_to_read) {
- X /* Get server command */
- X FD_ZERO (&rfds);
- X do {
- X FD_SET (sock_fd, &rfds);
- X timeout.tv_sec = timeout.tv_usec = response_timeout;
- X errno = 0;
- X value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
- X } while (value == -1 && errno == EINTR);
- X
- X if (value == 0) {
- X nbytes = 0;
- X printf ("Server response timeout.\n");
- X return CONN_TIMEOUT;
- X }
- X else if (value < 0) {
- X perror ("select() failed");
- X return -1;
- X }
- X
- X errno = 0;
- X /* Get server command */
- X bytes_read = read (sock_fd, &buf [4 - bytes_to_read], bytes_to_read);
- X if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
- X errno == ECONNREFUSED) {
- X nbytes = 0;
- X return CONN_ABORTED;
- X }
- X if (bytes_read > 0)
- X bytes_to_read -= bytes_read;
- X }
- X buf[3] = EOS;
- X cmd = atoi (buf);
- X i = 0;
- X do { /* Get # of bytes in actual message */
- X again1:
- X FD_ZERO (&rfds);
- X do {
- X FD_SET (sock_fd, &rfds);
- X timeout.tv_sec = timeout.tv_usec = response_timeout;
- X errno = 0;
- X value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
- X } while (value == -1 && errno == EINTR);
- X
- X if (value == 0) {
- X nbytes = 0;
- X printf ("Server response timeout.\n");
- X return CONN_TIMEOUT;
- X }
- X else if (value < 0) {
- X perror ("select() failed");
- X return -1;
- X }
- X
- X errno = 0;
- X if (read (sock_fd, &buf[i], 1) < 1) {
- X if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
- X errno == ECONNREFUSED) {
- X nbytes = 0;
- X return CONN_ABORTED;
- X }
- X if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
- X goto again1;
- X perror ("Protocol error in control string");
- X return -1;
- X }
- X i++;
- X } while (buf[i - 1] != ' ');
- X
- X buf[i - 1] = EOS;
- X nbytes = atoi (buf);
- X RESET (args);
- X i = 0;
- X do { /* Get filename (optional) */
- X again2:
- X FD_ZERO (&rfds);
- X do {
- X FD_SET (sock_fd, &rfds);
- X timeout.tv_sec = timeout.tv_usec = response_timeout;
- X errno = 0;
- X value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
- X } while (value == -1 && errno == EINTR);
- X
- X if (value == 0) {
- X nbytes = 0;
- X printf ("Server response timeout.\n");
- X return CONN_TIMEOUT;
- X }
- X else if (value < 0) {
- X perror ("select() failed");
- X return -1;
- X }
- X
- X errno = 0;
- X if (read (sock_fd, &args[i], 1) < 1) {
- X if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
- X errno == ECONNREFUSED)
- X return CONN_ABORTED;
- X if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
- X goto again2;
- X perror ("Protocol error in control string");
- X return -1;
- X }
- X ++i;
- X } while (args[i - 1] != '\n');
- X args[i - 1]= EOS;
- X return cmd;
- X}
- X
- X/*
- X Establish connection with listprocessor. The socket is marked as
- X non-blocking.
- X
- X Returns: the socket file descriptor, or -1 on error.
- X*/
- X
- Xint build_tcp_connection (char *host, int port)
- X{
- X int sock_fd, sendbuf = buffsiz, recvbuf = buffsiz, value = 1, nfds, naddr = 0;
- X struct sockaddr_in sin;
- X struct hostent *hostentry;
- X struct timeval timeout;
- X fd_set readfds, writefds;
- X
- X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
- X defined (apollo) || defined (unknown_port)
- X nfds = getdtablesize ();
- X# else
- X nfds = ulimit (UL_GDESLIM);
- X# endif
- X timeout.tv_sec = timeout.tv_usec = 0;
- X if (!(hostentry = gethostbyname (host))) { /* Host name failed; try IP */
- X sin.sin_addr.s_addr = inet_addr (host);
- X if (! (hostentry = gethostbyaddr ((char *) &sin.sin_addr,
- X sizeof (struct in_addr),
- X AF_INET))) {
- X printf ("%s: No such host.\n", host);
- X return -1;
- X }
- X }
- X
- X do { /* Check all addresses */
- X if ((sock_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
- X perror ("Could not create socket");
- X return -1;
- X }
- X if (setsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, (char *) &sendbuf,
- X sizeof (sendbuf)) < 0)
- X perror ("WARNING: Could not set send-buffer size: setsockopt() error");
- X if (setsockopt (sock_fd, SOL_SOCKET, SO_RCVBUF, (char *) &recvbuf,
- X sizeof (recvbuf)) < 0)
- X perror ("WARNING: Could not set receive-buffer size: setsockopt() error");
- X if (setsockopt (sock_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &value,
- X sizeof (value)) < 0)
- X perror ("WARNING: Cannot toggle keep-alive connections: setsockopt() error");
- X
- X# ifdef h_addr
- X memcpy ((char *) &sin.sin_addr.s_addr,
- X (char *) hostentry->h_addr_list[naddr++],
- X hostentry->h_length);
- X# else
- X memcpy ((char *) &sin.sin_addr.s_addr,
- X (char *) hostentry->h_addr,
- X hostentry->h_length);
- X# endif
- X sin.sin_family = AF_INET;
- X sin.sin_port = htons (port);
- X memset (sin.sin_zero, EOS, sizeof (sin.sin_zero));
- X printf ("Trying %s ... ", inet_ntoa (sin.sin_addr));
- X fflush (stdout);
- X if (connect (sock_fd, (struct sockaddr *) &sin,
- X sizeof (struct sockaddr_in)) < 0) {
- X if (errno != EINPROGRESS) {
- X# ifdef h_addr
- X if (!hostentry->h_addr_list[naddr]) {
- X# endif
- X perror ("");
- X close (sock_fd);
- X return -1;
- X# ifdef h_addr
- X }
- X else {
- X perror ("");
- X close (sock_fd);
- X continue;
- X }
- X# endif
- X }
- X FD_ZERO (&readfds);
- X FD_ZERO (&writefds);
- X do {
- X FD_SET (sock_fd, &readfds);
- X FD_SET (sock_fd, &writefds);
- X errno = 0;
- X value = select ((nfds > 0 ? nfds : 20), &readfds, &writefds, NULL,
- X &timeout);
- X } while (value == -1 && errno == EINTR);
- X
- X if (value < 0) {
- X perror ("select() error");
- X close (sock_fd);
- X return -1;
- X }
- X break; /* Successful connection */
- X }
- X else
- X break;
- X } while (007);
- X printf ("\n");
- X# ifdef NONBLOCKING_IO
- X if (fcntl (sock_fd, F_SETFL, (fcntl (sock_fd, F_GETFL, 0) | O_NDELAY)) < 0) {
- X perror ("Could not set non-blocking I/O");
- X close (sock_fd);
- X return -1;
- X }
- X# endif
- X# if defined (sco) || defined (M_XENIX) || defined (M_UNIX)
- X if (ioctl (sock_fd, I_SETSIG, S_INPUT) < 0) {
- X perror ("Cannot set SIGIO");
- X close (sock_fd);
- X return -1;
- X }
- X# else
- X# ifdef F_SETOWN
- X if (fcntl (sock_fd, F_SETOWN, getpid()) < 0) {
- X perror ("Cannot assign socket to process group");
- X close (sock_fd);
- X return -1;
- X }
- X# elif defined (SIOCSPGRP)
- X value = -getpid();
- X if (ioctl (sock_fd, SIOCSPGRP, (char *) &value) < 0) {
- X perror ("Cannot assign socket to process group");
- X close (sock_fd);
- X return -1;
- X }
- X# else
- X perror ("Cannot assign socket to process group");
- X close (sock_fd);
- X return -1;
- X# endif
- X# ifdef FASYNC
- X if (fcntl (sock_fd, F_SETFL, (fcntl (sock_fd, F_GETFL, 0) | FASYNC)) < 0) {
- X perror ("Cannot set asynchronous I/O for socket");
- X close (sock_fd);
- X return -1;
- X }
- X# elif defined (FIOASYNC)
- X value = 1;
- X if (ioctl (sock_fd, FIOASYNC, (char *) &value) < 0) {
- X perror ("Cannot set asynchronous I/O for socket");
- X close (sock_fd);
- X return -1;
- X }
- X# else
- X perror ("Cannot set asynchronous I/O for socket");
- X close (sock_fd);
- X return -1;
- X# endif
- X# endif
- X return sock_fd;
- X}
- X
- X/*
- X Handle signals; the client sends an '__abort__' command and exits, if sig
- X is SIGQUIT; '__abort__' causes the other end to shut down. On SIGINT, it
- X sends an abort operation and waits for the server's reply.
- X*/
- X
- Xint sighandle (int sig)
- X{
- X char ch = EOS, buf [MSGLEN + 1], waste [BUFSIZ];
- X int atoobmark, val, val2, once = 0, nfds;
- X long int discarded_bytes = 0;
- X fd_set readfds;
- X struct timeval timeout;
- X
- X if (sig == SIGHUP) {
- X signal (sig, (void (*)()) sighandle);
- X return 0;
- X }
- X else if (sig == SIGPIPE) {
- X if (!broken_pipe)
- X printf ("Broken pipe\n");
- X broken_pipe = 1;
- X signal (sig, (void (*)()) sighandle);
- X return 0;
- X }
- X else if (sig == SIGINT)
- X if (!sigint) {
- X if (no_abort_op) {
- X signal (sig, (void (*)()) sighandle);
- X return 0;
- X }
- X# ifndef NO_ABORT_OP
- X signal (sig, SIG_IGN);
- X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
- X defined (apollo) || defined (unknown_port)
- X nfds = getdtablesize ();
- X# else
- X nfds = ulimit (UL_GDESLIM);
- X# endif
- X do { /* Send abort op char as OOB data */
- X errno = 0;
- X val = send (sock_fd, "\03", 1, MSG_OOB);
- X } while (val == -1 &&
- X (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR));
- X if (val < 0)
- X perror ("send()");
- X else {
- X timeout.tv_sec = timeout.tv_usec = 0;
- X /* Look for the OOB mark; discard data before it; read the OOB byte
- X and message when at mark */
- X for (;;) {
- X FD_ZERO (&readfds);
- X do {
- X FD_SET (sock_fd, &readfds);
- X errno = 0;
- X if (once)
- X timeout.tv_sec = timeout.tv_usec = 3;
- X val = select ((nfds > 0 ? nfds : 20), &readfds, NULL, NULL,
- X &timeout);
- X if (val == 0 && once) { /* Reached end of socket */
- X write_to_fd (sock_fd, "\n",1); /* NOOP; resend prompt */
- X goto _abort;
- X }
- X } while (val == -1 && errno == EINTR);
- X
- X if (val < 0) {
- X perror ("select() error");
- X break;
- X }
- X
- X if (ioctl (sock_fd, SIOCATMARK, &atoobmark) < 0) {
- X perror ("FATAL: ioctl()"); /* OS bug if this happens */
- X break;
- X }
- X if (atoobmark) { /* Ready to get message */
- X int bytes_to_read = MSGLEN, bytes_read = 0, val;
- X do { /* Get OOB byte */
- X val = recv (sock_fd, &ch, 1, MSG_OOB);
- X if (val < 0 && errno && errno != EWOULDBLOCK && errno != EAGAIN
- X && errno != EINTR && errno != EINVAL) {
- X perror ("recv()"); /* OS bug if this happens */
- X break;
- X }
- X } while (val == -1 || ch != '#');
- X while (bytes_to_read) { /* Read message. i.e. bytes sent */
- X val = recv (sock_fd, &buf[bytes_read], bytes_to_read, NULL);
- X if (val > 0)
- X bytes_read += val,
- X bytes_to_read = MSGLEN - bytes_read;
- X }
- X buf [MSGLEN] = EOS;
- X fprintf (stderr, "Aborted after transferring %ld bytes.\n",
- X ((val = atoi (buf) - discarded_bytes) > 0 ? val :
- X atoi (buf)));
- X /* Now prompt follows */
- X break;
- X }
- X errno = 0;
- X /* Read and discard data until OOB mark */
- X val = read (sock_fd, waste, sizeof (waste));
- X if (val < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&
- X errno != EINTR) {
- X if (errno == 0) { /* Reached end of socket */
- X write_to_fd (sock_fd, "\n", 1); /* NOOP; resend prompt */
- X goto _abort;
- X }
- X else
- X perror ("read()");
- X exit (1);
- X }
- X if (val > 0) {
- X discarded_bytes += val;
- X /* Also send 0x3 once in the regular way just in case the server
- X finished sending before receiving our abort request */
- X if (!once) {
- X once = 1;
- X write_to_fd (sock_fd, "\03", 1);
- X }
- X }
- X }
- X }
- X# endif
- X _abort:
- X interrupted = 1;
- X cmd = MESSAGE;
- X signal (sig, (void (*)()) sighandle);
- X return 0;
- X }
- X check_sio = 0;
- X write_to_fd (sock_fd, "__abort__\n", 10);
- X close (sock_fd);
- X if (pipefp)
- X pclose (pipefp);
- X printf ("Connection closed.\n");
- X exit (sig);
- X}
- X
- X/*
- X Urgent data from server; read it and exit. Urgent data is received
- X when a connection is timed out or when the server shuts down.
- X*/
- X
- Xint urg_data (int sig)
- X{
- X int cmd;
- X
- X if (!check_sio) {
- X signal (sig, (void (*)()) urg_data);
- X return 0;
- X }
- X signal (sig, SIG_IGN);
- X if ((cmd = server_response (sock_fd)) >= 0)
- X if (cmd == CONN_ABORTED || cmd == CONN_TIMEOUT || cmd == CONN_CLOSED)
- X check_server_response (cmd, args),
- X read_from_fd (sock_fd, nbytes, NULL);
- X shutdown (sock_fd, 2);
- X kill (0, SIGHUP);
- X if (pipefp)
- X pclose (pipefp);
- X printf ("Connection closed.\n");
- X exit (cmd);
- X}
- X
- X/*
- X Alarm signals a server timeout.
- X*/
- X
- Xint alarm_clock (int sig)
- X{
- X timed_out = 1;
- X signal (sig, (void (*)()) alarm_clock);
- X}
- X
- X/*
- X Read from a socket and either echo to tty or save to a file.
- X
- X Returns: the actual number of bytes read on succes, or the negative of
- X that number (or -1) on error.
- X*/
- X
- Xlong int read_from_fd (int rfd, long int bytes_to_read, FILE *pipefp)
- X{
- X long int bytes_read = 0, total_bytes = 0;
- X int to_pipe = 1;
- X char *buf;
- X
- X timed_out = 0;
- X signal (SIGALRM, (void (*)()) alarm_clock);
- X alarm (response_timeout);
- X if (bytes_to_read <= 0)
- X return 0;
- X if ((buf = (char *) malloc (buffsiz * sizeof (char))) == NULL) {
- X printf ("malloc() failed while attempting to allocate %ld bytes\n",
- X buffsiz);
- X return -1;
- X }
- X errno = 0;
- X while (!interrupted &&
- X (bytes_read = read (rfd, buf, MIN (bytes_to_read, buffsiz))) <
- X bytes_to_read) {
- X if (bytes_read < 0 && errno && errno != EWOULDBLOCK &&
- X errno != EAGAIN && errno != EINTR
- X# ifdef ERESTART
- X && errno != ERESTART
- X# endif
- X ) {
- X char error [256];
- X switch (errno) {
- X case EBADF: sprintf (error, "Bad file number"); break;
- X case EFAULT: sprintf (error, "Bad address"); break;
- X case EFBIG: sprintf (error, "File limit reached"); break;
- X case EINVAL: sprintf (error, "Negative seek pointer"); break;
- X case EIO: sprintf (error, "I/O error"); break;
- X case ENOSPC: sprintf (error, "No space left on device"); break;
- X case ENXIO: sprintf (error, "No such device or address"); break;
- X case ERANGE: sprintf (error, "Bytes to read (%ld) out of \
- Xrange", bytes_to_read); break;
- X# ifdef ENETRESET
- X case ENETRESET: sprintf (error, "Network dropped connection"); break;
- X# endif
- X default: sprintf (error, "Error number %d", errno);
- X }
- X fprintf (stderr, "%s\n", error);
- X free ((char *) buf);
- X return -1;
- X }
- X else if (!pipefp && timed_out) {
- X printf ("Server response timeout.\n");
- X free ((char *) buf);
- X return (total_bytes > 0 ? -total_bytes : -1);
- X }
- X if (!interrupted && bytes_read > 0) {
- X total_bytes += bytes_read;
- X bytes_to_read -= bytes_read;
- X if (to_file) {
- X if (bytes_to_read < prompt_len)
- X write_to_fd (fileno (stdout),
- X &buf[bytes_read - prompt_len + bytes_to_read],
- X prompt_len - bytes_to_read),
- X to_file = 0;
- X if (write_to_fd (fd, buf,
- X (bytes_to_read < prompt_len ?
- X bytes_read - prompt_len + bytes_to_read :
- X bytes_read)) < 0) {
- X free ((char *) buf);
- X return (total_bytes > 0 ? -total_bytes : -1);
- X }
- X }
- X else if (pipefp) {
- X if (to_pipe && !broken_pipe) {
- X write_to_fd (fileno (pipefp), buf,
- X (bytes_to_read < prompt_len ?
- X bytes_read - prompt_len + bytes_to_read :
- X bytes_read));
- X if (errno) {
- X if (!broken_pipe && errno == EPIPE)
- X printf ("Broken pipe\n");
- X broken_pipe = 1;
- X }
- X }
- X if (bytes_to_read < prompt_len)
- X to_pipe = 0;
- X }
- X else
- X write_to_fd (fileno (stdout), buf, bytes_read);
- X }
- X errno = 0;
- X }
- X if (!interrupted && bytes_read > 0) {
- X total_bytes += bytes_read;
- X if (to_file && bytes_read > prompt_len) {
- X write_to_fd (fileno (stdout), &buf [bytes_read - prompt_len], prompt_len);
- X if (write_to_fd (fd, buf,
- X (bytes_read > prompt_len ?
- X bytes_read - prompt_len : bytes_read)) < 0) {
- X free ((char *) buf);
- X return (total_bytes > 0 ? -total_bytes : -1);
- X }
- X }
- X else if (pipefp) {
- X if (!broken_pipe) {
- X write_to_fd (fileno (pipefp), buf,
- X (bytes_read > prompt_len ? bytes_read - prompt_len
- X : 0));
- X if (errno && !broken_pipe && errno == EPIPE)
- X printf ("Broken pipe\n");
- X }
- X }
- X else
- X write_to_fd (fileno (stdout), buf, bytes_read);
- X }
- X if (fd >= 0)
- X close (fd),
- X fd = -1;
- X to_file = 0;
- X free ((char *) buf);
- X fflush (stdout);
- X if (pipefp)
- X fflush (pipefp);
- X signal (SIGALRM, SIG_IGN);
- X return total_bytes;
- X}
- X
- X/*
- X Write to a file descriptor (socket, or regular file).
- X
- X Returns: the actual number of bytes written on succes, or the negative of
- X that number (or -1) on error.
- X*/
- X
- Xlong int write_to_fd (int wfd, char *buf, long int bytes_to_write)
- X{
- X long int bytes_written, total_bytes = 0;
- X
- X if (bytes_to_write == 0)
- X return 0;
- X errno = 0;
- X while (!interrupted &&
- X (bytes_written = write (wfd, buf, bytes_to_write)) < bytes_to_write) {
- X if (bytes_written < 0 && errno && errno != EWOULDBLOCK && errno != EAGAIN
- X && errno != EINTR
- X# ifdef ERESTART
- X && errno != ERESTART
- X# endif
- X ) {
- X char error [256];
- X switch (errno) {
- X case EBADF: sprintf (error, "Bad file number"); break;
- X case EFAULT: sprintf (error, "Bad address"); break;
- X case EFBIG: sprintf (error, "File limit reached"); break;
- X case EINVAL: sprintf (error, "Negative seek pointer"); break;
- X case EIO: sprintf (error, "I/O error"); break;
- X case ENOSPC: sprintf (error, "No space left on device"); break;
- X case ENXIO: sprintf (error, "No such device or address"); break;
- X case ERANGE: sprintf (error, "Bytes to write (%ld) out of \
- Xrange", bytes_to_write); break;
- X case EPIPE: sprintf (error, "Server disappeared"); break;
- X# ifdef ENETRESET
- X case ENETRESET: sprintf (error, "Network dropped connection"); break;
- X# endif
- X default: sprintf (error, "Error number %d", errno);
- X }
- X fprintf (stderr, "%s\n", error);
- X if (bytes_written > 0)
- X total_bytes += bytes_written;
- X return (total_bytes > 0 ? -total_bytes : -1);
- X }
- X if (bytes_written > 0)
- X bytes_to_write -= bytes_written,
- X total_bytes += bytes_written,
- X buf += bytes_written;
- X errno = 0;
- X }
- X if (bytes_written > 0)
- X total_bytes += bytes_written;
- X return total_bytes;
- X}
- X
- X/*
- X Open a file for writing or appending. If 'test' is set, make sure
- X the file is writeable, notify the server and close the file; else prepare
- X for the transfer. When the server is inquiring about a file's write
- X permissions it sends zero bytes as the length of the message.
- X
- X Returns: 0 on succes, -1 otherwise.
- X*/
- X
- Xint open_file (char *file, int mode, int test)
- X{
- X char msg [4];
- X
- X if ((fd = open (file, O_CREAT | mode, 0600)) < 0)
- X to_file = 0,
- X printf ("%s: Permission denied.\n", args),
- X nbytes = prompt_len,
- X sprintf (msg, "%d", PERMISSION_DENIED);
- X else {
- X if (nbytes > 0)
- X to_file = 1,
- X printf ("Transferring %ld bytes to file %s...\n", nbytes - prompt_len,
- X file);
- X else
- X close (fd),
- X sprintf (msg, "%d", OK);
- X }
- X if (test)
- X if (write_to_fd (sock_fd, msg, strlen (msg)) < 0)
- X return -1;
- X return 0;
- X}
- X
- X/*
- X Identify the server's response and take appropriate action.
- X
- X Returns: 0 on success, -1 otherwise.
- X*/
- X
- Xint check_server_response (int cmd, char *file)
- X{
- X switch (cmd) {
- X case OK:
- X case CONNECT:
- X case SYNTAX_ERROR:
- X case INVALID_REQ:
- X case PEER_UNAVAIL:
- X case BAD_ARCHIVE:
- X case RESTRICTED_REQ:
- X case NOT_OWNER:
- X case SYS_ERROR:
- X case SERVER_BUSY:
- X case PASSWORD_REQUIRED:
- X case PERMISSION_DENIED:
- X case MESSAGE:
- X case CONTINUED:
- X case MORE_INPUT_REQUIRED:
- X case CONN_ABORTED:
- X case CONN_TIMEOUT:
- X case CONN_CLOSED: GENERAL_RESPONSES (cmd); break;
- X case TEST_FILE_PERMISSIONS: PRINTF (TEST_FILE_PERMISSIONS,
- X "Testing file permissions\n");
- X if (open_file (file, O_WRONLY | O_APPEND, 1)) return -1;
- X break;
- X case WRITE_TO_FILE_ASC: PRINTF (WRITE_TO_FILE_ASC,
- X "Writing to file (ASCII)\n");
- X if (open_file (file, O_WRONLY | O_TRUNC, 0)) return -1;
- X break;
- X case WRITE_TO_FILE_BIN: PRINTF (WRITE_TO_FILE_BIN,
- X "Writing to file (BIN)\n");
- X if (open_file (file, O_WRONLY | O_TRUNC, 0)) return -1;
- X break;
- X case APPEND_TO_FILE_ASC: PRINTF (APPEND_TO_FILE_ASC,
- X "Appending to file (ASCII)\n");
- X if (open_file (file, O_WRONLY | O_APPEND, 0)) return -1;
- X break;
- X case APPEND_TO_FILE_BIN: PRINTF (APPEND_TO_FILE_BIN,
- X "Appending to file (BIN)\n");
- X if (open_file (file, O_WRONLY | O_APPEND, 0)) return -1;
- X break;
- X default: printf ("Protocol error: %d\n", cmd); return -1;
- X }
- X return 0;
- X}
- X
- X/*
- X Check for input redirection, and if so check for for permissions too.
- X
- X Returns: the opened file descriptor on succes, -1 on error.
- X*/
- X
- Xint check_for_redirection (char *buf, char *infile)
- X{
- X char *r, *s, *b = buf;
- X int fd = 0, nquote = 0;
- X extern int literal;
- X
- X s = buf;
- X while (*s != EOS) {
- X prevch (s, b);
- X if (!nquote) {
- X if (literal)
- X *(s - 1) = *s,
- X *s = (char) 0x1;
- X else if (*s == '\'')
- X nquote = 1;
- X else if (*s == '"')
- X nquote = 2;
- X else if (*s == '<') {
- X if (!literal && infile[0] == EOS) {
- X RESET (infile);
- X sscanf (s + 1, "%s", infile);
- X if (infile [0] == EOS) {
- X printf ("Invalid null input redirect\n");
- X return -1;
- X }
- X if ((fd = open (infile, O_RDONLY)) < 0) {
- X printf ("%s: No such file or inadequate permissions\n", infile);
- X return -1;
- X }
- X r = s + 1; /* Remove < and file name */
- X while (*r != EOS && (*r == ' ' || *r == '\t')) ++r;
- X while (*r != EOS && !isspace (*r)) ++r;
- X sprintf (s, "%s", r);
- X --s;
- X }
- X }
- X }
- X else if ((nquote == 1 && *s == '\'') ||
- X (nquote == 2 && *s == '"')) {
- X if (!literal)
- X nquote = 0;
- X else
- X *(s - 1) = *s,
- X *s = (char) 0x1;
- X }
- X ++s;
- X }
- X if (nquote) {
- X printf ("Mismatched quotes\n");
- X strcpy (buf, "\n");
- X if (fd > 0)
- X close (fd);
- X return -1;
- X }
- X return fd;
- X}
- X
- X/*
- X Check for pipe.
- X
- X Returns: the open file pointer, or NULL.
- X*/
- X
- XFILE *check_for_pipe (char *buf)
- X{
- X char cmd [1024], *s = buf, *b = buf, nch;
- X int nquote = 0;
- X FILE *pipe = NULL;
- X
- X RESET (cmd);
- X pliteral = literal = 0;
- X while (*s != EOS) {
- X if (*s == (char) 0x1) {
- X ++s;
- X continue;
- X }
- X nch = nextch (s);
- X if (!nquote) {
- X if (*s == '\'' || *s == '"') {
- X if (nch != (char) 0x1)
- X nquote = (*s == '\'' ? 1 : 2);
- X }
- X else if (*s == '|') {
- X if (nch != (char) 0x1 && cmd[0] == EOS) {
- X sscanf (s + 1, "%s", cmd);
- X if (cmd [0] == EOS) {
- X printf ("Invalid null pipe\n");
- X strcpy (buf, "\n");
- X return NULL;
- X }
- X strcpy (cmd, s + 1);
- X strcpy (s, "\n");
- X pipe = (FILE *) popen (cmd, "w");
- X }
- X }
- X }
- X else if ((nquote == 1 && *s == '\'') ||
- X (nquote == 2 && *s == '"')) {
- X if (nch != (char) 0x1)
- X nquote = 0;
- X }
- X ++s;
- X }
- X for (s = buf; *s != EOS; ++s)
- X if (*s == 0x1)
- X *s = *(s - 1),
- X *(s - 1) = '\\';
- X if (nquote)
- X printf ("Mismatched quotes\n"),
- X strcpy (buf, "\n");
- X return pipe;
- X}
- X
- X/*
- X Return the previous character from the current position in the
- X string. Set 'pliteral' to 1 if that previous character is escaped with \ and
- X 'literal' to 1 if the current character is escaped with \.
- X In the comments, ^ means "beginning of the string", ? matches any character
- X except \, * matches absolutely any character and x is the current position.
- X*/
- X
- Xint prevch (char *s, char *b)
- X{
- X return
- X ((s) <= (b) ?
- X (pliteral = literal = 0, *(s)) : /* ^x */
- X (((s) - 1) == (b) ?
- X (*((s) - 1) == '\\' ? (pliteral = !(literal = 1), *((s) - 1)) /* ^\x */
- X : (pliteral = literal = 0, *((s) - 1))) /* ^?x */
- X : (*(s) == '\\' ?
- X (*((s) - 2) == '\\' ? (pliteral = !(literal = 0), *((s) - 1)) /* \*\ */
- X : (*((s) - 1) == '\\' ? (pliteral = !(literal = 1), *((s) - 2)) /* ?\\ */
- X : (pliteral = literal = 0, *((s) - 1)))) /* ??\ */
- X : (*((s) - 1) == '\\' ?
- X (*((s) - 2) == '\\' ?
- X (((s) - 2) == (b) ? (pliteral = !(literal = 0), *((s) - 1)) /* ^\\x */
- X : (*((s) - 3) == '\\' ? (pliteral = literal = 1,*((s) - 2)) /* \\\x */
- X : (pliteral = !(literal = 0), *((s) - 1)))) /* ?\\x */
- X : (((s) - 2) == (b) ? (pliteral = !(literal = 1),*((s) - 2)) /* ^?\x */
- X : (*((s) - 3) == '\\' ? (pliteral = literal = 1, *((s) - 2)) /* \?\x */
- X : (pliteral = !(literal = 1), *((s) - 2))))) /* ??\x */
- X : (*((s) - 2) == '\\' ? (pliteral = !(literal = 0),*((s) - 1)) /* \?x */
- X : (pliteral = literal = 0, *((s) - 1))))))); /* ??x */
- X}
- X
- X/*
- X Return the next character from the current position. The current character
- X is guarranteed not to be a literal. In the comments below * matches
- X absolutely any character, ? matches anything but EOS, $ is the EOS and
- X x marks the current position. Also set 'nliteral' to 1 if the next character
- X is escaped with \.
- X*/
- X
- Xint nextch (char *s)
- X{
- X return
- X (*((s) + 1) == EOS ? (nliteral = 0, EOS) /* x$ */
- X : (*((s) + 1) == '\\' ?
- X (*((s) + 2) == EOS ? (nliteral = 0, *((s) + 1)) /* x\$ */
- X : (nliteral = 1, *((s) + 2))) /* x\? */
- X : (nliteral = 0, *((s) + 1)))); /* x* */
- X}
- X#endif
- *-*-END-of-src/ilp.c-*-*
- echo x - src/list.c
- sed 's/^X//' >src/list.c <<'*-*-END-of-src/list.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | MAILING LIST MAIL-DISTRIBUTION PROGRAM |
- X | |
- X | Version 5.1 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X NOTE: Anything appearing in capital letters refers to #define's in the
- X header files provided.
- X
- X PURPOSE: Create mailing lists. Members of the list send messages to
- X them, and each of these messages is forwarded to the rest of the members.
- X Any message(s) not from subscribers are returned to the original senders,
- X or can be forwarded to MANAGER. Messages from "undesired" senders can be
- X ignored by placing their email addresses in the IGNORED file (this would
- X usually include root and the list's login name to avoid infinite loops).
- X Distributed may be automatically archived.
- X
- X OVERVIEW: A mailing list resides in a subdirectory of HOMEDIR/lists
- X whose name is the list's alias (in the aliases file) in capital letters.
- X When the program is killed or it abnormally dies, a message
- X is sent to MANAGER (if using UCB mail) along with a copy of the current
- X report file (more on that below). Use the -1 flag when running the
- X program. The mailing list to be processed is given as argument to the
- X -L option in upper case. Any progress is reported to the list's REPORT_LIST
- X file and to the administrator's terminal. All messages sent to this list are
- X saved in the MBOX file. The program can be run as stand-alone, or in
- X conjunction with the other programs provided (start, serverd and listproc).
- X Please note that a line beginning with "From " and another one beginning
- X with "From: " must appear in the header of each message, and a blank line
- X must separate the header from the body of the message. Mailing lists
- X can be linked with peers and have access to news groups. A crash recovery
- X mechanism is built into the system, so that when the system is aborted
- X while a delivery is taking place, it will resume delivery from where
- X it left off.
- X
- X COMMAND LINE OPTIONS:
- X -r: Restricted mail; since it is possible to have another distribution
- X list at some other site as a subscriber, then the following problem
- X arises: if a message is coming from a member of the other list, his/
- X her message was forwarded to the members of that list from the other
- X site; we do not want to send this message back to them, because they
- X will receive this message twice. Therefore, when this flag is on,
- X for every message received, its sender is checked against a list
- X of "restricted" mail addresses (a subset of the subscribers). If a
- X match is found, then mail is forwarded to the people listed in the
- X filename following this email address -- for the appropriate format
- X see below. If no match is found, then the message is forwarded to
- X to all of the subscribers. See also below.
- X -1: Execute only once; this is used when the program is running in
- X conjunction with listproc, in which case execution is interchanged
- X and controlled by the serverd program.
- X -e: Echo reports to the screen.
- X -s: Do not check for subscriptions.
- X -p: By default, replies to posted (to news) messages go to the list;
- X this option forces replies to be forwarded to the original author.
- X -P: By default, replies to distributed messages go to the list; this option
- X forces replies to be forwarded to the original author.
- X -m: Usually, each outgoing message has a single recipient. This switches
- X to multiple recipients -- the argument to it is the number of
- X multiple recipients to be included in this message.
- X -v: Display the version number of this package.
- X -f: Forward any message(s) from unsubscribed senders to the list's
- X owner. This way, any ordinary user account can be used as the list's
- X address.
- X -L: The argument following is the list name to process.
- X -D: Turn debug on. A transaction of the last email sent out is kept
- X in the files HOMEDIR/sent and HOMEDIR/received. This assumes
- X use of the 'system' mail method.
- X -M: List is moderated. Incoming messages go to owner unless
- X they are from owner in which case they get posted.
- X -d: Send out the digest even though it's not full
- X -i: Send out a digest to one user (whose name is the argument)
- X -Z: Turn off automatic compression of archived message.
- X
- X DISCLAIMER: If for any reason during the use of this program, implied
- X or not, you happen to die, or suffer any injury of any kind (physical
- X or mental), I, Mr. Anastasios Kotsikonas, AM NOT RESPONSIBLE at all.
- X In fact, I AM NOT RESPONSIBLE FOR ANYTHING that may happen to you, or
- X your computer and operating system.
- X
- X PLEASE: If you upgrade the code, send me a copy, and do not even attempt to
- X put your name for credit. Send to tasos@cs.bu.edu or tasos@bucsf.bu.edu.
- X
- X EXIT CODES:
- X 0: OK
- X 1: Could not open or lock file
- X 2: SIGINT signal
- X 3: Command line option error
- X 4: Syntax error in file
- X 5: Could not spawn
- X 6: Shutdown request
- X 7: Restart request
- X 8: Received system signal
- X 9: Too many multiple recipients
- X 10: Could not deliver mail
- X 11: Malloc failed
- X 12: Cannot fork
- X 13: Socket connection problem
- X 14: Semaphore error
- X 15: Cannot setuid, setgid
- X 16: Internal error
- X
- X ENJOY!!!
- X
- X Approximate algorithm:
- X {
- X If DIGEST_TMP file exists
- X send it to digest subscribers
- X
- X If the -d flag is on
- X make a digest
- X send it to digest subscribers
- X
- X Place a lock so that no other list program will access any files.
- X Read LIST_MAIL_FILE
- X If new message(s) have arrived then {
- X Lock LIST_MAIL_FILE so catmail can't append to it
- X Append messages to MBOX and truncate LIST_MAIL_FILE
- X Unlock LIST_MAIL_FILE
- X
- X For each message do {
- X If the person is in the IGNORED file, go on to the next message.
- X If the person sending it is subscribed (listed in SUBSCRIBERS) then
- X If the person does not acknowledge his/her message, he/she
- X never receives his/her message back
- X
- X If the -m flag is on then
- X If the article comes from someone who is not the owner
- X forward to the owner
- X go on to next message
- X Else
- X remove headers accumulated in passing to the moderator and back
- X figure out original sender and subject
- X
- X If the -r flag is on then
- X check if the sender is listed in RESTRICTED
- X If so then
- X forward mail to all people listed in the file after the
- X restricted-sender's address
- X Else
- X distribute to all people in SUBSCRIBERS
- X Else
- X distribute to all people in SUBSCRIBERS, NEWSF (only to those
- X newsgroups that are supposed to received messages) and PEERS
- X according to the following:
- X Email from regular SUBSCRIBERS is sent to NEWS and PEERS as well
- X Email from news is sent to SUBSCRIBERS and PEERS
- X Email from peers is sent to SUBSCRIBERS and NEWS
- X Else if it news feed (listed in NEWSF)
- X distribute to SUBSCRIBERS
- X Else
- X if -f specified, forward it to MANAGER; otherwise return the
- X message to the sender.
- X Archive message is requested.
- X }
- X Remove mail files.
- X }
- X Repeat process after IDLE_TIME, or die if -1 specified.
- X }
- X
- X Required files:
- X SUBSCRIBERS <-- The list of subscribed people
- X ALIASES <-- Aliases of email addresses of subscribers, news & peers
- X NEWSF <-- List of news groups
- X PEERS <-- List of peer lists
- X RESTRICTED <-- Addresses of senders whose messages
- X require special handling (usually
- X addresses of other lists): mail is
- X forwarded only to people found in the
- X file after the sender's address; see below
- X IGNORED <-- The list of undesired people
- X
- X Input files:
- X LIST_MAIL_FILE <-- File where new messages go
- X MAIL_COPY <-- Copy of this file (actual work file)
- X MSG_NO <-- Current message count
- X DIGEST_NO <-- Current digest count
- X SUBSCRIBERS
- X RESTRICTED
- X IGNORED
- X
- X Output files:
- X MBOX <-- A log of all messages sent to date
- X REPORT_LIST <-- Progress report
- X HEADERS <-- A log of all emails sent (just the sender's address)
- X MSG <-- Body of message (no header)
- X MSG_NO <-- Write last message count
- X DIGEST_NO <-- Write last digest count
- X MAILFORWARD <-- Completed message (with header and a copy
- X of MSG) to be forwarded
- X
- X Format of the SUBSCRIBERS file:
- X One entry per line; each entry is the full email address of the subscriber
- X as it appears in the "From " field, followed by the word "ACK" (in which
- X case his/her message will be sent back to him/her as an acknowledgement)
- X "NOACK" (the opposite), POSTPONE (no mail will be sent until the
- X user changes mode again), or DIGEST (digests are periodically sent),
- X followed by a string that plays the role of a password, followed by either
- X YES or NO which play the role of the conceal attribute, followed by the
- X subscriber's name. Do not include any blank lines.
- X
- X Format of the RESTRICTED file:
- X One entry per line; each entry is the full email address of the
- X subscriber, followed by a file name where email addresses of recipients
- X are listed (just like in the SUBSCRIBERS file).When mail arrives from a
- X sender listed in the RESTRICTED file and the -r flag is on, then mail
- X will not be forwarded to SUBSCRIBERS, but instead to the people
- X listed in the file following the restricted-sender's address. Example:
- X tasos@bucsf.bu.edu /grad/tasos/.recipients
- X tasos@cs.bu.edu /grad/tasos/.otherrecipients
- X If the recipient file given is the word "NONE", then no one will receive
- X any messages. This is useful in the case that other distribution sites
- X are subscribers and do forward the message back to the sender,
- X in which case we protect ourselves from multiple reception of the same
- X messages.
- X For example, when two (or more) lists are mutual subscribers, and a
- X message originated by someone in our list, this message, after being
- X distributed locally, is sent to the other list; if the other site does
- X send messages back to the sender, this message will be forwarded to us
- X to be distributed again, something which is highly undesirable.
- X This precludes that the other site sends messages identified only by
- X their original senders, something which is unlikely but possible.
- X In this case, we would put our list as one of the entries in the
- X RESTRICTED file, with the word NONE next to it. Do not include
- X any blank lines.
- X
- X Format of the PEERS file:
- X One entry per line -- the email address of the peer list, followed
- X by its mail mode (NOACK), followed by the remote alias (how the peer list
- X is known in the remote host), followed by the email address of the
- X remote server that handles the remote peer list.
- X
- X Format of the NEWSF file:
- X One entry per line -- the email address of the news group, followed
- X by its mail mode (POSTPONE or NOACK), followed by the news group's name.
- X
- X Format of the IGNORED file:
- X One entry per line -- the email addresses of the people whose messages
- X are to be ignored. This is a good place to put root, sys and other
- X such undesired logins. See doc/server.nr for information.
- X
- X Format of the ALIASES file:
- X One entry per line -- the new alias followed by the email address the
- X user is subscribed with. See doc/server.nr for information.
- X
- X*/
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#ifdef SYSLOG
- X# ifdef ultrix
- X# include <sys/syslog.h>
- X# else
- X# include <syslog.h>
- X# endif
- X#endif
- X#include <ctype.h>
- X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
- X && !defined (sequent) && !defined (unknown_port)
- X# include <malloc.h>
- X#endif
- X#include <string.h>
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <sys/stat.h>
- X#if !defined (sequent) && !defined (__NeXT__) && !defined (__convex__) && \
- X !defined (apollo) && !defined (i386) && !defined (unknown_port)
- X# include <sys/termio.h>
- X#endif
- X#ifndef sun
- X# include <sys/ioctl.h>
- X#endif
- X#include <fcntl.h>
- X#include <signal.h>
- X#include <time.h>
- X#include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X#include "defs.h"
- X#include "list.h"
- X#include "struct.h"
- X#include "global.h"
- X#if defined (__NeXT__) || defined (unknown_port)
- X# include "next.h"
- X#endif
- X
- X#ifdef TCP_IP
- X# include <sys/socket.h>
- X# include <netdb.h>
- X# include <netinet/in.h>
- Xstruct in_addr localaddr;
- X#else
- Xchar *localaddr;
- X#endif
- X
- X#ifdef GO_INTERACTIVE
- X# include <sys/ipc.h>
- X# include <sys/sem.h>
- X#endif
- X
- X/*
- X Function prototypes:
- X*/
- X
- X#ifdef __STDC__
- X# include <stdarg.h>
- Xextern int syscom (char *, ...);
- Xextern char *tsprintf (char *, ...);
- X#else
- X# include <varargs.h>
- Xextern int syscom ();
- Xextern char *tsprintf ();
- X#endif
- X#ifndef __NeXT__
- Xextern long int atoi (char *);
- X#else
- Xextern int atoi (const char *);
- X#endif
- Xextern int sys_config (FILE *, SYS *);
- Xextern void report_progress (FILE *, char *, int);
- Xextern void setup_string (char *, char *, char *);
- Xextern void init_signals (void);
- Xextern void catch_signals (void);
- Xextern void extract_origin (char *);
- Xextern void extract_address (char *);
- Xextern int get_list_id (char *, SYS *, int);
- Xextern void clean_request (char *);
- Xextern int _getopt (int, char **, char *);
- Xextern char *upcase (char *);
- Xextern char *locase (char *);
- Xextern void shrink (char *);
- Xextern void free_remote (REMOTE **);
- Xextern void distribute (FILE *, void (*)(char *, char *, BOOLEAN, BOOLEAN),
- X FILE *, char *, char *, char *, char *, BOOLEAN);
- Xextern BOOLEAN extract_subscriber (FILE *, char *, BOOLEAN);
- Xextern BOOLEAN sysmail (char *);
- Xextern BOOLEAN strinstr (char *, char *);
- Xextern BOOLEAN ignore_sender (FILE *, char *, FILE *, BOOLEAN);
- Xextern BOOLEAN owner_listed (char *, char *, char *, FILE *);
- Xextern int lock_file (char *, int, int, BOOLEAN);
- Xextern void unlock_file (int);
- Xextern int otoi (char *);
- Xextern BOOLEAN mkdir1 (char *, char *, char *);
- Xextern BOOLEAN make_indexes (char *, char *, char *, char *, char *);
- Xextern int re_strcmp (char *, char *, char *);
- Xextern char *_strstr (char *, char *);
- Xextern char *skip_to_word (char *, int);
- Xextern char *mystrdup (char *);
- Xextern int echo (char *, char *);
- Xextern int echo_append (char *, char *);
- Xextern int mv (char *, char *);
- Xextern int cp (char *, char *);
- Xextern int cat_append (char *, char *);
- Xextern int touch (char *);
- Xextern int ucb_strftime (char *, int, char *, struct tm *);
- Xextern long int write_to_fd (int, char *, long int);
- Xextern void escape_re (char *);
- Xextern int P (int, int);
- Xextern int V (int, int);
- X
- Xvoid main (int, char **, char **);
- Xvoid create_header (FILE **, char *, char *, char *, char *, char *,
- X BOOLEAN, BOOLEAN, BOOLEAN);
- Xvoid create_multi_recipient_header (FILE **, char *, char *, char *, char *,
- X char *, int);
- Xvoid create_news_header (FILE **, char *, char *, char *, char *, char *);
- Xvoid create_gate_header (FILE **, char *, char *, char *, char *, char *,
- X char *);
- Xvoid process_message (char *, char *, BOOLEAN, BOOLEAN);
- Xvoid distributions (BOOLEAN, char *, char *, BOOLEAN, char *, char *,
- X char *, char *, char *, long int, BOOLEAN);
- XBOOLEAN do_distribute (char *, FILE *, char *, BOOLEAN, char *, BOOLEAN, char *,
- X char *, char *, char *, char *, FILE *,
- X BOOLEAN, BOOLEAN, long int, BOOLEAN, BOOLEAN, BOOLEAN,
- X BOOLEAN);
- XBOOLEAN unprocessed_users (char *, char *, FILE *);
- Xvoid update_unprocessed (char *, BOOLEAN, BOOLEAN, int);
- Xvoid update_unprocessed_messages (char *);
- XBOOLEAN copy_msg (FILE *, char *, BOOLEAN, char *, long int, BOOLEAN, BOOLEAN);
- XBOOLEAN sendmail (char *, BOOLEAN, BOOLEAN, int, int, char *);
- Xvoid usage (void);
- Xvoid list_config (char *);
- Xvoid version (void);
- Xint gexit (int);
- Xvoid fill_text (FILE *, char *);
- XBOOLEAN read_recipient (FILE *, char *, char *, char *, BOOLEAN);
- Xlong int count_lines_in_file (FILE *);
- Xvoid digest_make (BOOLEAN);
- Xvoid digest_distribute (void);
- Xvoid do_archive (char *, char *, char *, BOOLEAN);
- Xvoid farch (char *, char *, char *, char *, char *, char *);
- Xvoid reject_archive (char *, char *);
- XBOOLEAN get_volume (char *, int *, int *);
- XBOOLEAN get_archive_name (char *, char *);
- XBOOLEAN limit_exceeded (char *, char *, char *);
- X
- X/*
- X The control structure of the mail-distributor. Check if mail has arrived.
- X If so, copy it to MAIL_COPY and proceed to lower level.
- X*/
- X
- Xvoid main (int argc, char **argv, char **envp)
- X{
- X struct stat stat_buf;
- X char *options = "1fvrL:em:spPDMdi:S:Z", tmp[MAX_LINE], error [MAX_LINE];
- X int rlfd, i, j, c;
- X long int sig_mask;
- X FILE *f;
- X extern char *optarg, *getenv();
- X extern int optopt;
- X#ifdef TCP_IP
- X struct hostent *lhost;
- X#endif
- X
- X prog = argv[0];
- X while ((c = _getopt (argc, argv, options)) != EOF)
- X switch ((char) c) {
- X case '1': execute_once = TRUE; break;
- X case 'f': errors_to_owner = TRUE; break;
- X case 'r': send_to_subscribers = FALSE; break;
- X case 'L': list_alias = upcase (optarg); break;
- X case 'e': tty_echo = TRUE; break;
- X case 's': do_not_check_subscriptions = TRUE; break;
- X case 'S': sid = atoi (optarg); break;
- X case 'p': article_replies_to_author = TRUE; break;
- X case 'P': message_replies_to_author = TRUE; break;
- X case 'v': version ();
- X case 'D': debug = TRUE; break;
- X case 'd': force_digest = TRUE; break;
- X case 'i': one_digest = optarg; break;
- X case 'M': is_moderated = TRUE; break;
- X case 'm':
- X multi_recip = TRUE;
- X if ((maxrecipients = atoi (optarg)) < 1)
- X fprintf (stderr, "-m %d -- yeah, right!\n", maxrecipients),
- X exit (3);
- X break;
- X case 'Z': no_compression = TRUE; break;
- X case ':':
- X fprintf (stderr, "list: Option '%c' requires an argument.\n", optopt);
- X exit (3);
- X case '?':
- X default:
- X usage ();
- X }
- X if ((mask = getenv ("ULISTPROC_UMASK")))
- X umask (otoi (mask));
- X else
- X mask = "066",
- X umask (S_IRWXG|S_IRWXO); /* 600 */
- X if (!(archives_mask = getenv ("ULISTPROC_ARCHIVES_UMASK")))
- X archives_mask = mask;
- X init_signals();
- X catch_signals();
- X list_config (list_alias);
- X#ifdef SYSLOG
- X openlog ("ListProcessor: list", LOG_NDELAY
- X# ifndef i386
- X |LOG_NOWAIT
- X# endif
- X , SYSLOG);
- X# ifndef ultrix
- X setlogmask (LOG_UPTO (LOG_INFO));
- X# endif
- X#else
- X if ((report = fopen (report_listf, "a")) == NULL)
- X if ((report = fopen (REPORT_LIST, "a")) == NULL)
- X fprintf (stderr, "list: Could not open %s and %s\n", report_listf,
- X REPORT_LIST),
- X exit (1);
- X else
- X chmod (REPORT_LIST, 384); /* 600 */
- X else
- X chmod (report_listf, 384); /* 600 */
- X#endif
- X if (list_alias == NULL)
- X report_progress (report, "\nlist: No list to process", TRUE),
- X exit (3);
- X nlists = sys_config (report, &sys);
- X if ((listid = get_list_id (list_alias, &sys, nlists)) < 0)
- X report_progress (report, tsprintf ("\nlist: Unknown list %s", list_alias),
- X TRUE),
- X exit (3);
- X if (!execute_once)
- X printf ("%s", COPYRIGHT);
- X if (sys.options & USE_ENV_VAR) {
- X if ((sys.mail.method = (char *) malloc (256 * sizeof (char))) == NULL)
- X report_progress (report, "\nmain(): malloc() failed", TRUE),
- X exit (11);
- X sprintf (sys.mail.method, "env - %s=%s %s ", sys.mail.env_var,
- X sys.lists[listid].address, sys.mail.mail_prog);
- X }
- X
- X if ((msg_no = fopen (msg_nof, "r")) != NULL)
- X fscanf (msg_no, "%d %d\n", &public_msg, &returned_msg),
- X fclose (msg_no);
- X if ((digest_no = fopen (digest_nof, "r")) != NULL)
- X fscanf (digest_no, "%d\n", &digest_msg),
- X fclose (digest_no);
- X
- X if (!tty_echo) {
- X j = -1;
- X#if defined (TIOCNOTTY) && defined (SIGTTOU) && defined (SIGTTIN)
- X if ((i = open ("/dev/tty", 2)) >= 0)
- X j = ioctl (i, TIOCNOTTY, 0),
- X close (i);
- X#endif
- X if (j < 0 &&
- X#ifdef svr4
- X setsid ()
- X#else
- X# ifdef SETPGRP_NEEDS_ARGS
- X setpgrp (0, 0)
- X# else
- X setpgrp ()
- X# endif
- X#endif
- X < 0)
- X report_progress (report, "WARNING: could not detach from tty", TRUE);
- X }
- X
- X if (multi_recip)
- X if ((multi_recipients = (char **) malloc (maxrecipients * sizeof (char *)))
- X == NULL)
- X report_progress (report, "\nmain(): malloc() failed", TRUE),
- X exit (11);
- X
- X if ((f = fopen (PID_LIST, "w")) != NULL)
- X fprintf (f, "%d", getpid()),
- X fclose (f);
- X signal (SIGINT, (void (*)()) gexit);
- X signal (SIGALRM, SIG_IGN);
- X#ifdef TCP_IP
- X if (gethostname (hostname, sizeof (hostname)))
- X report_progress (report, tsprintf ("\nmain(): gethostname() failed: errno \
- X%d", errno), TRUE),
- X exit (16);
- X if (!(lhost = gethostbyname (hostname)))
- X report_progress (report, tsprintf ("\nmain(): gethostbyname() failed: errno\
- X %d", errno), TRUE),
- X exit (16);
- X memcpy ((char *) &localaddr, (char *) lhost->h_addr, lhost->h_length);
- X#else
- X localaddr = LOCAL_ADDR;
- X strcpy (hostname, HOSTNAME);
- X#endif
- X
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("main", SEM_LISTFILES);
- X# ifndef ERROR_MAIL_ANALYSIS
- X sprintf (tmp, "%s.t", subscribersf);
- X if (cp (subscribersf, tmp))
- X gexit (16);
- X strcpy (subscribersf, tmp);
- X sprintf (tmp, "%s.t", newsf);
- X if (cp (newsf, tmp))
- X gexit (16);
- X strcpy (newsf, tmp);
- X sprintf (tmp, "%s.t", peersf);
- X if (cp (peersf, tmp))
- X gexit (16);
- X strcpy (peersf, tmp);
- X OUT_OF_CRITICAL_SECTION ("main", SEM_LISTFILES);
- X# endif
- X IN_CRITICAL_SECTION ("main", SEM_DLVR_MAIL);
- X#endif
- X
- X sprintf (error, "recipients of digest %d", digest_msg);
- X if (unprocessed_users (unprocessed_digestf, error, report)) {
- X /* Was interrupted while distributing a digest */
- X /* USER CONTIBUTED CODE: Warren Burstein */
- X OPEN_FILE (subscribers, subscribersf, "r", "main");
- X OPEN_FILE (news, newsf, "r", "main");
- X OPEN_FILE (peers, peersf, "r", "main");
- X OPEN_FILE (restricted, restrictedf, "r", "main");
- X
- X digest_distribute ();
- X
- X fclose (subscribers);
- X fclose (news);
- X fclose (peers);
- X fclose (restricted);
- X }
- X
- X if ((force_digest || one_digest) &&
- X (!stat (digest_msgf, &stat_buf) && stat_buf.st_size > 0)) {
- X OPEN_FILE (subscribers, subscribersf, "r", "main");
- X OPEN_FILE (news, newsf, "r", "main");
- X OPEN_FILE (peers, peersf, "r", "main");
- X OPEN_FILE (restricted, restrictedf, "r", "main");
- X
- X if (force_digest) {
- X digest_make (TRUE);
- X digest_distribute ();
- X }
- X else { /* Make a partial digest, send to one_digest */
- X char subject[MAX_LINE];
- X FILE *forwardmail = NULL; /* Completed message to be forwarded */
- X
- X digest_make (FALSE);
- X
- X sprintf (subject, "%s partial digest %d", sys.lists[listid].alias,
- X digest_msg);
- X
- X create_header (&forwardmail, mailforwardf, sys.lists[listid].address,
- X sys.lists[listid].address, one_digest, subject,
- X FALSE, FALSE, FALSE);
- X if (copy_msg (forwardmail, msgf, FALSE, sys.lists[listid].address, 0,
- X FALSE, FALSE))
- X sendmail (one_digest, FALSE, FALSE, 0, 0, mailforwardf);
- X }
- X fclose (subscribers);
- X fclose (news);
- X fclose (peers);
- X fclose (restricted);
- X }
- X
- X do {
- X if (!stat (list_mail_f, &stat_buf) && stat_buf.st_size > 0) {
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X#ifndef NO_LOCKS
- X if ((rlfd = lock_file (list_mail_f, O_RDWR, 0, FALSE)) < 0)
- X report_progress (report, tsprintf ("\nmain(): Cannot open or lock %s",
- X list_mail_f), TRUE),
- X gexit (1); /* Cannot lock file, so exit, regardless of execute_once */
- X#endif
- X if (!sys.lists[listid].max_messages) {
- X if (cp (list_mail_f, mail_copyf))
- X exit (16);
- X unlink (list_mail_f);
- X touch (list_mail_f); /* rewrite file */
- X chmod (list_mail_f, /*416*/ 0666 & (0666 ^ otoi (mask)));
- X }
- X else if (limit_exceeded (limitsf, list_mail_f, mail_copyf)) {
- X#ifndef NO_LOCKS
- X unlock_file (rlfd);
- X#endif
- X break;
- X }
- X if (cat_append (mail_copyf, mboxf))
- X exit (16);
- X chmod (mboxf, 384);
- X if (cp (mail_copyf, unprocessed_messages))
- X exit (16);
- X echo_append ("", mboxf);
- X touch (list_moderated_f);
- X chmod (list_moderated_f, /*416*/ 0666 & (0666 ^ otoi (mask)));
- X
- X#ifndef NO_LOCKS
- X unlock_file (rlfd);
- X#endif
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X
- X OPEN_FILE (mail, mail_copyf, "r", "main");
- X OPEN_FILE (subscribers, subscribersf, "r", "main");
- X OPEN_FILE (news, newsf, "r", "main");
- X OPEN_FILE (peers, peersf, "r", "main");
- X OPEN_FILE (restricted, restrictedf, "r", "main");
- X OPEN_FILE (ignored, ignoredf, "r", "main");
- X OPEN_FILE (headers, headersf, "a", "main");
- X report_progress (report, NEW_ARRIVAL, FALSE);
- X distribute (mail,
- X (void (*)(char *, char *, BOOLEAN, BOOLEAN)) process_message,
- X report, subscribersf, newsf, peersf, aliasesf,
- X#ifdef ERROR_MAIL_ANALYSIS
- X FALSE
- X#else
- X TRUE
- X#endif
- X );
- X fclose (mail); /* Done */
- X fclose (subscribers);
- X fclose (news);
- X fclose (peers);
- X fclose (restricted);
- X fclose (ignored);
- X fclose (headers);
- X shrink (message_idsf);
- X shrink (checksumsf);
- X unlink (unprocessed_messages);
- X unlink (mail_copyf); /* Done delivering */
- X }
- X else if (!execute_once) /* No mail to deliver */
- X if (sys.frequency > 0)
- X sleep (sys.frequency);
- X } while (!execute_once);
- X#ifdef GO_INTERACTIVE
- X# ifndef ERROR_MAIL_ANALYSIS
- X unlink (subscribersf);
- X unlink (newsf);
- X unlink (peersf);
- X# else
- X OUT_OF_CRITICAL_SECTION ("main", SEM_LISTFILES);
- X# endif
- X OUT_OF_CRITICAL_SECTION ("main", SEM_DLVR_MAIL);
- X#endif
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X#ifdef SYSLOG
- X closelog ();
- X#else
- X fclose (report);
- X#endif
- X free_remote (&rlists);
- X if (multi_recip)
- X free ((char **) multi_recipients);
- X unlink (PID_LIST);
- X exit (0);
- X}
- X
- X/*
- X Create a mail header. If this is a reply to a rejected posting, 'copy_owner'
- X should be TRUE. If reply_to_sender is TRUE, message will reply to sender,
- X otherwise to list.
- X*/
- X
- Xvoid create_header (FILE **f, char *filename, char *sender, char *originator,
- X char *recipient, char *subject, BOOLEAN copy_owner,
- X BOOLEAN reply_to_sender, BOOLEAN error_condition)
- X{
- X char error [MAX_LINE];
- X char origin [MAX_LINE];
- X char reply_to [MAX_LINE];
- X#ifdef LIST_ALIAS_IN_SUBJECT
- X char *s, *sb;
- X#endif
- X#ifdef NEED_DATE
- X char date [80];
- X# ifdef ultrix
- X time_t time_is;
- X# else
- X long int time_is;
- X# endif
- X struct tm *t;
- X#endif
- X MATCHED_PREC_HEADER *m = matched_prec_header;
- X
- X strcpy (origin, originator);
- X locase (origin);
- X strcpy (reply_to, sender);
- X extract_address (reply_to);
- X OPEN_FILE (*f, filename, "w", "create_header");
- X locase (recipient);
- X if (subject [0] != EOS && subject [strlen (subject) - 1] == '\n')
- X subject [strlen (subject) - 1] = EOS;
- X if (sys.options & USE_TELNET) {
- X fprintf (*f, "HELO %s\nMAIL From: <%s>\nRCPT To: <%s>\n",
- X#ifdef ZMAILER
- X/*
- X# ifdef TCP_IP
- X (char *) inet_ntoa (localaddr),
- X# else
- X localaddr,
- X# endif
- X Use either the local address or the host name.
- X*/
- X hostname,
- X#else
- X "",
- X#endif
- X sys.lists[listid].address, recipient);
- X if (copy_owner)
- X fprintf (*f, "RCPT To: <%s>\n", sys.lists[listid].owner);
- X fprintf (*f, "DATA\n");
- X }
- X if (message_id[0] != EOS)
- X fprintf (*f, "Message-Id: %s\n", message_id);
- X#ifdef NEED_DATE
- X time (&time_is);
- X t = localtime (&time_is);
- X ucb_strftime (date, 1024, "%a, %e %b %Y %T %Z", t);
- X fprintf (*f, "Date: %s\n", date);
- X#endif
- X#ifndef NO_ERRORS_TO
- X fprintf (*f, "Errors-To: %s\n", sys.lists[listid].owner);
- X#endif
- X while (m) {
- X if (!strncmp ("Reply-To:", m->line, strlen ("Reply-To:")))
- X break;
- X m = m->next;
- X }
- X if (!m)
- X fprintf (*f, "Reply-To: %s\n",
- X ((reply_to_sender | message_replies_to_author) ?
- X reply_to : sys.lists[listid].address));
- X fprintf (*f, "Originator: %s\nSender: %s\nPrecedence: %s\nFrom: %s\nTo: %s\n",
- X origin, sys.lists[listid].address, sys.mail.precedence, sender,
- X recipient);
- X if (copy_owner)
- X fprintf (*f, "Cc: %s\n", sys.lists[listid].owner);
- X#ifdef LIST_ALIAS_IN_SUBJECT
- X if (!error_condition) {
- X /* Remove previous tag and amassing Re: */
- X if ((s = _strstr (subject, tsprintf ("[%s:", sys.lists[listid].alias)))) {
- X sprintf (s, "%s", ((sb = strchr (s, ']')) ? sb + 2 : ""));
- X if (re_strcmp ("^[ \t]*[Rr][Ee]:[ \t]+[Rr][Ee]:", subject, NULL) > 0)
- X sprintf (subject, "%s", subject + 4);
- X }
- X fprintf (*f, "Subject: [%s:%d] %s\n", sys.lists[listid].alias, public_msg,
- X subject);
- X }
- X else
- X fprintf (*f, "Subject: %s%s\n", ERROR_CONDITION, subject);
- X#else
- X fprintf (*f, "Subject: %s%s\n", (error_condition ? ERROR_CONDITION : ""),
- X subject);
- X#endif
- X fprintf (*f, "X-Listprocessor-Version: %s\n", VERSION);
- X if (sys.lists[listid].comment[0] != EOS)
- X fprintf (*f, "X-Comment: %s\n", sys.lists[listid].comment);
- X m = matched_prec_header;
- X while (m)
- X fprintf (*f, "%s", m->line),
- X m = m->next;
- X fprintf (*f, "\n");
- X}
- X
- X/*
- X Create a mail header with multiple recipients.
- X*/
- X
- Xvoid create_multi_recipient_header (FILE **f, char *filename, char *sender,
- X char *originator, char *recipient,
- X char *subject, int nrecipients)
- X{
- X char origin [MAX_LINE];
- X char reply_to [MAX_LINE];
- X int i;
- X MATCHED_PREC_HEADER *m = matched_prec_header;
- X#ifdef LIST_ALIAS_IN_SUBJECT
- X char *s, *sb;
- X#endif
- X#ifdef NEED_DATE
- X char date [80];
- X# ifdef ultrix
- X time_t time_is;
- X# else
- X long int time_is;
- X# endif
- X struct tm *t;
- X#endif
- X
- X strcpy (origin, originator);
- X locase (origin);
- X strcpy (reply_to, sender);
- X extract_address (reply_to);
- X if (subject [0] != EOS && subject [strlen (subject) - 1] == '\n')
- X subject [strlen (subject) - 1] = EOS;
- X OPEN_FILE (*f, filename, "w", "create_multi_recipient_header");
- X if (sys.options & USE_TELNET) {
- X fprintf (*f, "HELO %s\nMAIL From: <%s>\n",
- X#ifdef ZMAILER
- X/*
- X# ifdef TCP_IP
- X (char *) inet_ntoa (localaddr),
- X# else
- X localaddr,
- X# endif
- X Use either the local address or the host name.
- X*/
- X hostname,
- X#else
- X "",
- X#endif
- X sys.lists[listid].address);
- X for (i = 0; i < nrecipients; i++)
- X fprintf (*f, "RCPT To: <%s>\n", multi_recipients[i]),
- X free ((char *) multi_recipients[i]);
- X fprintf (*f, "DATA\n");
- X }
- X if (message_id[0] != EOS)
- X fprintf (*f, "Message-Id: %s\n", message_id);
- X#ifdef NEED_DATE
- X time (&time_is);
- X t = localtime (&time_is);
- X ucb_strftime (date, 1024, "%a, %e %b %Y %T %Z", t);
- X fprintf (*f, "Date: %s\n", date);
- X#endif
- X#ifndef NO_ERRORS_TO
- X fprintf (*f, "Errors-To: %s\n", sys.lists[listid].owner);
- X#endif
- X while (m) {
- X if (!strncmp ("Reply-To:", m->line, strlen ("Reply-To:")))
- X break;
- X m = m->next;
- X }
- X if (!m)
- X fprintf (*f, "Reply-To: %s\n",
- X (message_replies_to_author ? reply_to : sys.lists[listid].address));
- X fprintf (*f, "Originator: %s\nSender: %s\nPrecedence: %s\nFrom: %s\nTo: %s\n",
- X origin, sys.lists[listid].address, sys.mail.precedence, sender,
- X recipient);
- X#ifdef LIST_ALIAS_IN_SUBJECT
- X /* Remove previous tag and amassing Re: */
- X if ((s = _strstr (subject, tsprintf ("[%s:", sys.lists[listid].alias)))) {
- X sprintf (s, "%s", ((sb = strchr (s, ']')) ? sb + 2 : ""));
- X if (re_strcmp ("^[ \t]*[Rr][Ee]:[ \t]+[Rr][Ee]:", subject, NULL) > 0)
- X sprintf (subject, "%s", subject + 4);
- X }
- X fprintf (*f, "Subject: [%s:%d] %s\n", sys.lists[listid].alias, public_msg,
- X subject);
- X#else
- X fprintf (*f, "Subject: %s\n", subject);
- X#endif
- X fprintf (*f, "X-Listprocessor-Version: %s\n", VERSION);
- X if (sys.lists[listid].comment[0] != EOS)
- X fprintf (*f, "X-Comment: %s\n", sys.lists[listid].comment);
- X m = matched_prec_header;
- X while (m)
- X fprintf (*f, "%s", m->line),
- X m = m->next;
- X fprintf (*f, "\n");
- X}
- X
- X/*
- X Create a news header for a message to be posted.
- X*/
- X
- Xvoid create_news_header (FILE **f, char *filename, char *sender,
- X char *originator, char *group, char *subject)
- X{
- X char origin [MAX_LINE];
- X char reply_to [MAX_LINE];
- X MATCHED_PREC_HEADER *m = matched_prec_header;
- X#ifdef NEED_DATE
- X char date [80];
- X# ifdef ultrix
- X time_t time_is;
- X# else
- X long int time_is;
- X# endif
- X struct tm *t;
- X#endif
- X
- X strcpy (origin, originator);
- X locase (origin);
- X strcpy (reply_to, sender);
- X extract_address (reply_to);
- X if (subject [0] != EOS && subject [strlen (subject) - 1] == '\n')
- X subject [strlen (subject) - 1] = EOS;
- X OPEN_FILE (*f, filename, "w", "create_news_header");
- X locase (group);
- X fprintf (*f, "Path: %s\nNewsgroups: %s\nDistribution: world\n\
- XOrganization: %s\nOriginator: %s\n",
- X (article_replies_to_author ? reply_to : sys.lists[listid].address),
- X group, sys.organization, origin);
- X if (message_id[0] != EOS)
- X fprintf (*f, "Message-Id: %s\n", message_id);
- X#ifdef NEED_DATE
- X time (&time_is);
- X t = localtime (&time_is);
- X ucb_strftime (date, 1024, "%a, %e %b %Y %T %Z", t);
- X fprintf (*f, "Date: %s\n", date);
- X#endif
- X while (m) {
- X if (!strncmp ("Reply-To:", m->line, strlen ("Reply-To:")))
- X break;
- X m = m->next;
- X }
- X if (!m)
- X fprintf (*f, "Reply-To: %s\n",
- X (article_replies_to_author ? reply_to : sys.lists[listid].address));
- X fprintf (*f, "Sender: %s\nFrom: %s\nSubject: %s\n",
- X sys.lists[listid].address, sender, subject);
- X m = matched_prec_header;
- X while (m)
- X fprintf (*f, "%s", m->line),
- X m = m->next;
- X fprintf (*f, "\n");
- X}
- X
- X/*
- X Create a gateway header.
- X*/
- X
- Xvoid create_gate_header (FILE **f, char *filename, char *sender,
- X char *originator, char *recipient,
- X char *group, char *subject)
- X{
- X char origin [MAX_LINE];
- X char reply_to [MAX_LINE];
- X MATCHED_PREC_HEADER *m = matched_prec_header;
- X#ifdef NEED_DATE
- X char date [80];
- X# ifdef ultrix
- X time_t time_is;
- X# else
- X long int time_is;
- X# endif
- X struct tm *t;
- X#endif
- X
- X strcpy (origin, originator);
- X locase (origin);
- X strcpy (reply_to, sender);
- X extract_address (reply_to);
- X if (subject [0] != EOS && subject [strlen (subject) - 1] == '\n')
- X subject [strlen (subject) - 1] = EOS;
- X OPEN_FILE (*f, filename, "w", "create_gate_header");
- X locase (group);
- X if (sys.options & USE_TELNET)
- X fprintf (*f, "HELO %s\nMAIL From: <%s>\nRCPT To: <%s>\nDATA\n",
- X#ifdef ZMAILER
- X/*
- X# ifdef TCP_IP
- X (char *) inet_ntoa (localaddr),
- X# else
- X localaddr,
- X# endif
- X Use either the local address or the host name.
- X*/
- X hostname,
- X#else
- X "",
- X#endif
- X sys.lists[listid].address, recipient);
- X#ifndef NO_ERRORS_TO
- X fprintf (*f, "Errors-To: %s\n", sys.lists[listid].owner);
- X#endif
- X fprintf (*f, "Newsgroups: %s\nDistribution: world\nOrganization: %s\n\
- XOriginator: %s\n", group, sys.organization, origin);
- X if (message_id[0] != EOS)
- X fprintf (*f, "Message-Id: %s\n", message_id);
- X#ifdef NEED_DATE
- X time (&time_is);
- X t = localtime (&time_is);
- X ucb_strftime (date, 1024, "%a, %e %b %Y %T %Z", t);
- X fprintf (*f, "Date: %s\n", date);
- X#endif
- X while (m) {
- X if (!strncmp ("Reply-To:", m->line, strlen ("Reply-To:")))
- X break;
- X m = m->next;
- X }
- X if (!m)
- X fprintf (*f, "Reply-To: %s\n",
- X (article_replies_to_author ? reply_to : sys.lists[listid].address));
- X fprintf (*f, "Sender: %s\nFrom: %s\nTo: %s\nSubject: %s\n",
- X sys.lists[listid].address, sender, recipient, subject);
- X m = matched_prec_header;
- X while (m)
- X fprintf (*f, "%s", m->line),
- X m = m->next;
- X fprintf (*f, "\n");
- X}
- X
- X/*
- X The heart of the distribution. Since we are now at the beginning of the
- X message (as guaranteed by distribute ()), gather the rest of the message
- X -- that is until the beginning of the next message, or EOF. Note that
- X only the "From: ", "Originator: " and "Subject: " lines from the header
- X are saved.
- X The beginning of the next and every message is "From ". The actual
- X text of each message is separated from its header by a blank line (universal
- X format). The message is processed only if the sender is not listed in
- X IGNORED.
- X The entire message is stored in MSG. To distribute the message, prepare
- X a new header; the completed message is stored in MAILFORWARD. Actually,
- X for each subscriber we prepare a different header (different "To:" field)
- X and append MSG to MAILFORWARD. Distribute that mail to the members,
- X or, either return it to the sender if he/she is not subscribed, or
- X forward it to MANAGER if -f specified. Messages from MAILER_DAEMON are
- X always forwarded to MANAGER. A message from a mailer daemon is identified
- X by the presence of MAILER_DAEMON anywhere in the sender's email address,
- X to cover local and remote mailer daemon addresses. Please look at the
- X documentation for defs.h for the syntax of the MAILER_DAEMON string.
- X The parameter "sender" is used for report purposes and when we are sending
- X the sender's message back to him/her.
- X Messages from regular subscribers are sent to peer lists and news groups.
- X Messages from news groups are only distributed to local subscribers and
- X peer lists. Finally, messages from peer lists are distributed locally
- X and may be posted to news groups.
- X In the case of restricted mail, check if the sender is listed in
- X RESTRICTED; if so, forward the message to the people listed in the
- X filename found after the restricted-sender's address in RESTRICTED.
- X Each public message (legitimate message) is automatically archived.
- X*/
- X
- Xchar *msgs[] = { /* USER CONTRIBUTED CODE: Warren Burstein */
- X "If you forward it back to the list, it will be distributed without the",
- X "paragraphs above the dashed line. You may edit the Subject: line and",
- X "the text of the message before forwarding it back.",
- X "",
- X "If you edit the messages you receive into a digest, you will need to",
- X "remove these paragraphs and the dashed line before mailing the result",
- X "to the list. Finally, if you need more information from the author of",
- X "this message, you should be able to do so by simply replying to this",
- X "note.",
- X "", NULL
- X};
- X
- Xvoid process_message (char *sender, char *linecopy, BOOLEAN address_ok,
- X BOOLEAN sender_subscribed)
- X{
- X char line [MAX_LINE]; /* ... from the current message */
- X char sent_date [MAX_LINE];
- X char senders_subject [MAX_LINE]; /* the sender's subject */
- X char subject_copy [MAX_LINE]; /* a copy of the subject */
- X char original_sender [MAX_LINE]; /* as it appears in his message */
- X char originator [MAX_LINE]; /* Holds the Originator: address */
- X char reply_to [MAX_LINE]; /* Holds the Reply-To: address */
- X char id_copy [MAX_LINE]; /* Holds the Message-Id: */
- X char recipients [MAX_LINE]; /* Holds the To: addresses */
- X char ccrecipients [MAX_LINE]; /* Holds the Cc: addresses */
- X char keywords [MAX_LINE]; /* Holds the Keywords: */
- X char precedence [MAX_LINE]; /* Holds the Precedence: */
- X char match [MAX_LINE];
- X char match2 [MAX_LINE];
- X char error [MAX_LINE];
- X char received [MAX_LINE];
- X char sender_copy [MAX_LINE];
- X char *at = NULL;
- X char *sumf = NULL;
- X char sum [MAX_LINE];
- X FILE *forwardmail = NULL; /* completed message to be forwarded */
- X FILE *msg = NULL;
- X FILE *header = NULL;
- X FILE *in, *out, *f;
- X BOOLEAN already_sent = FALSE;
- X BOOLEAN message_forwarded = FALSE;
- X BOOLEAN mailer_daemon;
- X BOOLEAN susp_subject;
- X BOOLEAN fake_mail = TRUE;
- X BOOLEAN control_article = FALSE;
- X long int lines_to_skip = 0; /* skip lines of incoming message */
- X long int sig_mask;
- X MATCHED_PREC_HEADER *out_header = matched_prec_header;
- X PRECIOUS_HEADER *pheader;
- X int request_found, i;
- X
- X /* gets set if anyone wants digests */
- X append_to_digest = sys.lists[listid].options & ARCHIVE_DIGEST;
- X
- X line[0] = sent_date[0] = recipients[0] = ccrecipients[0] = keywords[0] =
- X senders_subject[0] = subject_copy[0] = originator[0] = archive_name[0] =
- X reply_to[0] = message_id[0] = id_copy[0] = received[0] = precedence[0] =
- X RESET (original_sender);
- X
- X strcpy (sender_copy, sender);
- X upcase (sender_copy);
- X while (matched_prec_header) /* Free previous precious header lines */
- X out_header = matched_prec_header->next,
- X free ((char *) matched_prec_header->line),
- X free ((MATCHED_PREC_HEADER *) matched_prec_header),
- X matched_prec_header = out_header;
- X
- X /* Remove message header, but store the "From: " and "Subject: " fields to
- X be used later when sending the message to all subscribers. Also, preserve
- X user-defined header lines. */
- X
- X OPEN_FILE (header, headerf, "w", "process_message");
- X fprintf (header, "%s", linecopy);
- X while (!feof (mail) && line[0] != '\n') {
- X strcpy (match, "\\1");
- X if (re_strcmp (FROM, line, match) > 0) {
- X strcpy (original_sender, line + strlen (match)); /* Save From: */
- X original_sender [strlen (original_sender) - 1] = EOS; /* \n -> \0 */
- X if (strchr (original_sender, '|') || original_sender[0] == ':' ||
- X strchr (original_sender, '`'))
- X original_sender[0] = EOS; /* protect against Trojans */
- X }
- X
- X else if (re_strcmp (DATE, line, match) > 0)
- X strcpy (sent_date, line + strlen (match)), /* Save Date: */
- X sent_date [strlen (sent_date) - 1] = EOS; /* \n -> \0 */
- X
- X else if (re_strcmp (TO, line, match) > 0)
- X strcpy (recipients, line + strlen (match)), /* Save To: */
- X recipients [strlen (recipients) - 1] = EOS; /* \n -> \0 */
- X
- X else if (re_strcmp (CC, line, match) > 0)
- X strcpy (ccrecipients, line + strlen (match)), /* Save Cc: */
- X ccrecipients [strlen (ccrecipients) - 1] = EOS; /* \n -> \0 */
- X
- X else if (re_strcmp (KEYWORDS, line, match) > 0)
- X strcpy (keywords, line + strlen (match)), /* Save Keywords: */
- X keywords [strlen (keywords) - 1] = EOS; /* \n -> \0 */
- X
- X else if (re_strcmp (SUBJECT, line, match) > 0) {
- X strcpy (senders_subject, line + strlen (match)); /* Save Subject: */
- X senders_subject [strlen (senders_subject) - 1] = EOS; /* \n -> \0 */
- X while (isspace (senders_subject[0]))
- X sprintf (senders_subject, "%s", senders_subject + 1);
- X strcpy (subject_copy, senders_subject);
- X }
- X
- X else if (re_strcmp (ORIGIN, line, match) > 0)
- X strcpy (originator, line + strlen (match)), /* Remove "Originator: " */
- X originator [strlen (originator) - 1] = EOS, /* \n -> \0 */
- X extract_origin (originator),
- X upcase (originator);
- X
- X else if (re_strcmp (ARCHIVE_NAME, line, match) > 0)
- X /* Remove "Archive-Name: " */
- X strcpy (archive_name, line + strlen (match)),
- X extract_origin (archive_name);
- X
- X else if (re_strcmp (REPLY_TO, line, match) > 0)
- X strcpy (reply_to, line + strlen (match)), /* Remove "Reply-To: " */
- X reply_to [strlen (reply_to) - 1] = EOS, /* \n -> \0 */
- X extract_origin (reply_to),
- X upcase (reply_to);
- X
- X else if (re_strcmp (PRECEDENCE, line, match) > 0)
- X strcpy (precedence, line + strlen (match)), /* Remove "Precedence: " */
- X precedence [strlen (precedence) - 1] = EOS, /* \n -> \0 */
- X upcase (precedence);
- X
- X else if (re_strcmp (RECEIVED, line, match) > 0) { /* Check for fake mail */
- X strcpy (received, line + strlen (match));
- X received [strlen (received) - 1] = EOS;
- X sscanf (received, "%s %s", error, received); /* Get host after "from" */
- X upcase (received); /* Relay host */
- X if (fake_mail && (at = strchr (sender_copy + 1, '@')))
- X if (re_strcmp (at + 1, received, NULL) > 0)
- X fake_mail = FALSE;
- X }
- X
- X else if (re_strcmp (CONTROL, line, NULL) > 0)
- X control_article = TRUE;
- X
- X else if (re_strcmp (MESSAGE_ID1, line, NULL) > 0 ||
- X re_strcmp (MESSAGE_ID2, line, NULL) > 0 ||
- X re_strcmp (MESSAGE_ID3, line, NULL) > 0)
- X strcpy (message_id, line + strlen ("Message-") + 4),
- X message_id [strlen (message_id) - 1] = EOS; /* \n -> \0 */
- X
- X else { /* Check if precious header line */
- X pheader = sys.lists[listid].header;
- X while (pheader) {
- X if (!strncmp (line, pheader->line, strlen (pheader->line))) {
- X if (! (out_header =
- X (MATCHED_PREC_HEADER *) malloc (sizeof (MATCHED_PREC_HEADER))))
- X report_progress (report, "\nprocess_message(): malloc() failed",
- X TRUE),
- X gexit (11);
- X if (! (out_header->line =
- X (char *) malloc ((strlen (line) + 1) * sizeof (char ))))
- X report_progress (report, "\nprocess_message(): malloc() failed",
- X TRUE),
- X gexit (11);
- X strcpy (out_header->line, line);
- X out_header->next = matched_prec_header;
- X matched_prec_header = out_header;
- X }
- X pheader = pheader->next;
- X }
- X }
- X
- X RESET (line);
- X fgets (line, MAX_LINE - 2, mail);
- X fprintf (header, "%s", line);
- X }
- X fclose (header);
- X
- X /* Gather message into MSG; check if we have reached the next message,
- X or EOF; also check for possible requests sent to the list */
- X OPEN_FILE (msg, msgf, "w", "process_message");
- X RESET (line);
- X request_found = -1;
- X while (!feof (mail) &&
- X (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {
- X if (!strcmp (line, ".\n"))
- X PREPEND (".", line);
- X fprintf (msg, "%s", line);
- X upcase (line);
- X if (line [0] != EOS && line [strlen (line) - 1] == '\n')
- X line [strlen (line) - 1] = EOS;
- X if (request_found < 0 && line[0] != EOS) { /* First non-empty line */
- X strcpy (match, "\\1");
- X if (re_strcmp (REQUESTS, line, match) > 0) { /* Possible request */
- X#ifdef LIST_CHECKING_FOR_REQUESTS
- X strcpy (match2, "\\2");
- X re_strcmp (REQUESTS, line, match2); /* Get list specified (if any) */
- X if (match2[0] == EOS)
- X request_found = TRUE; /* Request does not take 'list' arg */
- X else if (get_list_id (match2, &sys, nlists) >= 0)
- X#endif
- X request_found = TRUE;
- X }
- X if (request_found < 0)
- X request_found = FALSE;
- X }
- X fgets (line, MAX_LINE - 2, mail);
- X }
- X fclose (msg);
- X
- X strcpy (linecopy, line); /*** VERY IMPORTANT: we are now at the next msg ***/
- X
- X if (!address_ok) { /* Abort message */
- X NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS (sender, "process_message", TRUE);
- X return;
- X }
- X
- X if (control_article) {
- X report_progress (report, "Control message ignored", TRUE);
- X return;
- X }
- X if (sender_subscribed != PEER &&
- X re_strcmp (LOW_PRECEDENCES, precedence, NULL) > 0) {
- X NOTIFY_OWNER_OF_MSG_IGNORED ("Low Precedence: %s message ignored.",
- X precedence);
- X return;
- X }
- X /* Check the IGNORED file */
- X if (ignore_sender (ignored, sender, report, FALSE)) {
- X NOTIFY_OWNER_OF_MSG_IGNORED ("The sender's address (%s) matches entries\n\
- Xin the list's .ignored file.", sender);
- X return;
- X }
- X if (originator[0] != EOS) /* Check for mail loop using Originator: */
- X if (ignore_sender (ignored, originator, report, FALSE)) {
- X NOTIFY_OWNER_OF_MSG_IGNORED ("The Originator: address (%s) matches \
- Xentries\nin the list's .ignored file.", originator);
- X return;
- X }
- X if (reply_to[0] != EOS) /* Check for mail loop using Reply-To: */
- X if (ignore_sender (ignored, reply_to, report, FALSE)) {
- X NOTIFY_OWNER_OF_MSG_IGNORED ("The Reply-To: address (%s) matches entries\n\
- Xin the list's .ignored file.", reply_to);
- X return;
- X }
- X if (message_id[0] != EOS) { /* Check for mail loop using Message-Id: */
- X strcpy (id_copy, message_id);
- X upcase (id_copy);
- X if (message_ids = fopen (message_idsf, "r")) {
- X if (ignore_sender (message_ids, id_copy, report, TRUE)) {
- X fclose (message_ids);
- X NOTIFY_OWNER_OF_MSG_IGNORED ("The Message-Id: %s matches entries\n\
- Xin the list's .message.ids file.", id_copy);
- X return;
- X }
- X fclose (message_ids);
- X }
- X }
- X /* Check for mail loop using Message-Id: and X-Listprocessor-Version: in
- X the body */
- X mailer_daemon = strinstr (MAILER_DAEMON, sender) ||
- X (original_sender[0] != EOS && strinstr (MAILER_DAEMON, original_sender)) ||
- X *sender == EOS;
- X susp_subject = (senders_subject[0] != EOS &&
- X strinstr (SUSP_SUBJECT, senders_subject));
- X
- X if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report) &&
- X !mailer_daemon && !susp_subject) {
- X OPEN_FILE (msg, msgf, "r", "process_message");
- X sumf = mystrdup (tmpnam (NULL));
- X while (!feof (msg)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, msg);
- X if (re_strcmp (MESSAGE_ID1, line, NULL) > 0 ||
- X re_strcmp (MESSAGE_ID2, line, NULL) > 0 ||
- X re_strcmp (MESSAGE_ID3, line, NULL) > 0) {
- X strcpy (id_copy, line + strlen ("Message-") + 4);
- X id_copy [strlen (id_copy) - 1] = EOS; /* \n -> \0 */
- X upcase (id_copy);
- X if (message_ids = fopen (message_idsf, "r")) {
- X if (ignore_sender (message_ids, id_copy, report, TRUE)) {
- X fclose (msg);
- X fclose (message_ids);
- X NOTIFY_OWNER_OF_MSG_IGNORED ("A message with Message-Id: %s \
- X(appearing\nin the body) matches entries in the list's .message.ids file.",
- X id_copy);
- X return;
- X }
- X fclose (message_ids);
- X }
- X }
- X else if (re_strcmp (LISTPROC_ID, line, NULL) > 0) {
- X fclose (msg);
- X NOTIFY_OWNER_OF_MSG_IGNORED ("Found X-Listprocessor-Version: id in \
- Xmessage body; message ignored", "");
- X return;
- X }
- X }
- X fclose (msg);
- X }
- X
- X if (!sumf)
- X sumf = mystrdup (tmpnam (NULL));
- X /* Check for mail loop by comparing checksums */
- X syscom ("tr -d ' \t\\012' < %s | sum | awk '{ print $1 }' > %s",
- X msgf, sumf);
- X OPEN_FILE (msg, sumf, "r", "process_message");
- X fscanf (msg, "%s", sum);
- X fclose (msg);
- X if (atoi (sum) == 0) {
- X NOTIFY_OWNER_OF_MSG_IGNORED ("This message has no body.", "");
- X return;
- X }
- X if (msg = fopen (checksumsf, "r")) {
- X if (ignore_sender (msg, sum, report, TRUE)) {
- X fclose (msg);
- X NOTIFY_OWNER_OF_MSG_IGNORED ("The body of the message has a checksum \
- Xmatching those messages already\ndistributed.", "");
- X return;
- X }
- X fclose (msg);
- X }
- X unlink (sumf);
- X free ((char *) sumf);
- X
- X if (sender_subscribed == NEWS)
- X if (ignore_sender (peers, originator, report, TRUE)) {
- X NOTIFY_OWNER_OF_MSG_IGNORED ("The Originator: address (%s) in the \
- Xarticle\nmatches entries in the list's .ignored file.", originator);
- X return;
- X }
- X
- X if (originator[0] == EOS) /* Fresh message originating from this list */
- X sprintf (originator, "%s", sys.lists[listid].address);
- X upcase (originator);
- X
- X if (do_not_check_subscriptions && sender_subscribed == NOTSUBSCRIBED)
- X sender_subscribed = SUBSCRIBED;
- X if (sender_subscribed == NOTSUBSCRIBED || mailer_daemon || susp_subject ||
- X request_found > 0) {
- X /* Send error message to sender */
- X report_progress (report,
- X tsprintf ("Invalid message #%04d (%s). Forwarding error \
- Xmessage to %s.\n%s",
- X ++returned_msg,
- X (mailer_daemon ? "suspicious address" :
- X (susp_subject ? "suspicious subject" :
- X (request_found > 0 ? "request sensed" :
- X (sender_subscribed == NOTSUBSCRIBED ?
- X "sender not subscribed" :
- X "???")))),
- X ((mailer_daemon || susp_subject || errors_to_owner) ?
- X sys.lists[listid].owner : sender),
- X (*sender != EOS ? sender : "\"\"")), TRUE);
- X OPEN_FILE (msg_no, msg_nof, "w", "process_message");
- X fprintf (msg_no, "%d %d\n", public_msg, returned_msg);
- X fclose (msg_no);
- X OPEN_FILE (msg, msgf, "r", "process_message");
- X /* Prepare header */
- X create_header (&forwardmail, mailforwardf, sys.lists[listid].address,
- X originator,
- X ((mailer_daemon || susp_subject || errors_to_owner) ?
- X sys.lists[listid].owner : sender),
- X senders_subject, COPY_OWNER (ccerrors), FALSE, TRUE);
- X if (errors_to_owner || mailer_daemon || susp_subject)
- X fprintf (forwardmail, "\nRejected message: sent to %s by %s \
- Xfollows.\nReason for rejection: %s.\n",
- X sys.lists[listid].address, (*sender != EOS ? sender : "\"\""),
- X (mailer_daemon ? "suspicious address" :
- X (susp_subject ? "suspicious subject" :
- X (request_found > 0 ? "request sensed" :
- X (sender_subscribed == NOTSUBSCRIBED ? "sender not subscribed" :
- X "???")))));
- X else if (request_found > 0)
- X if (sender_subscribed != PEER && sender_subscribed != NEWS)
- X /* First line of msg contained a request; send it back w/ apologies */
- X fprintf (forwardmail, "\nWe are sorry, but this system sensed the \
- Xfollowing request which may have been\ninadvertedly sent to this list:\n\n%s\n\
- X\nIf your posting was intentional, please accept our apologies and resend your\
- X\nmail message, making sure you do not include anything that may look like a\
- X\nrequest in the first line of the body of the actual message. If this was \
- X\nindeed a request please resend it to %s\nYour entire message\nis copied \
- Xbelow.\n\n", match, sys.server.address);
- X else
- X report_progress (report, "Message from peer/news ignored: request \
- Xsensed\n", FALSE);
- X else {
- X fprintf (forwardmail, "%s: You are not subscribed to %s.\n\
- XYour message is returned to you unprocessed. If you want to subscribe,\n\
- Xsend mail to %s with the following request:\n\n\t\tsubscribe %s Your Name\n\n", sender, sys.lists[listid].address, sys.server.address,
- X sys.lists[listid].alias);
- X if (alternate_addresses) {
- X fprintf (forwardmail, "In addition, the system found the following \
- Xaddress(es) that resemble yours.\nIf one of these is you, please resend your \
- Xmessage from that one, or use the\n'set <list> address' request to change the \
- Xaddress you are subscribed with:\n\n");
- X for (i = 0; alternate_addresses[i]; ++i)
- X fprintf (forwardmail, "%s\n", alternate_addresses[i]),
- X free ((char *) alternate_addresses[i]);
- X free ((char **) alternate_addresses);
- X alternate_addresses = NULL;
- X fprintf (forwardmail, "\n");
- X }
- X }
- X
- X#ifdef ERROR_MAIL_ANALYSIS
- X if (mailer_daemon) { /* See if we should remove the user and/or log error */
- X char line [1024], matches [MAX_LINE], matches2 [MAX_LINE],
- X subj [MAX_LINE];
- X BOOLEAN fatal_subject;
- X
- X RESET (line);
- X rewind (msg);
- X strcpy (subj, subject_copy);
- X upcase (subj);
- X while (!feof (msg) &&
- X !_strstr (line, "UNSENT MESSAGE FOLLOWS") &&
- X !_strstr (line, "REJECTED MESSAGE") &&
- X !_strstr (line, "TRANSCRIPT OF MESSAGE FOLLOWS") &&
- X !_strstr (line, "RETURNED MAIL") &&
- X re_strcmp ("^RECEIVED:[ \t]", line, NULL) <= 0 &&
- X re_strcmp ("^REPLY-TO:[ \t]", line, NULL) <= 0 &&
- X re_strcmp ("^SENDER:[ \t]", line, NULL) <= 0 &&
- X re_strcmp ("^DATE:[ \t]", line, NULL) <= 0 &&
- X re_strcmp ("^TO:[ \t]", line, NULL) <= 0) {
- X fgets (line, 1023, msg);
- X upcase (line);
- X strcpy (matches, "\\1.*\\2");
- X strcpy (matches2, "\\1");
- X if (re_strcmp (errors, line, matches) > 0 ||
- X ((fatal_subject = re_strcmp (fatal_subjects, subj, matches2)) > 0 &&
- X ((atoi (matches2) >= (GRACE_PERIOD / 86400)) ||
- X matches2[0] == EOS))) {
- X /* Remove user if present */
- X char address [MAX_LINE], address_copy [MAX_LINE],_line [1024],
- X _address [MAX_LINE];
- X
- X# if (ERROR_MAIL_ANALYSIS == 9)
- X if (fatal_subject > 0) {
- X strcpy (matches, ".*\\1"); /* See if warning and get host name */
- X re_strcmp (warnings, line, matches);
- X if (re_strcmp ("^\\.\\*[a-zA-Z0-9_-]+\\.[a-zA-Z0-9.:_-]+$", matches, NULL) <= 0)
- X strcpy (matches, ".*\\1"); /* Hostname syntax failed */
- X }
- X if (matches [0] != EOS && matches [strlen (matches) - 1] == '\n')
- X matches [strlen (matches) - 1] = EOS;
- X# endif
- X if (re_strcmp ("\\[|\\]", matches, NULL) > 0) /* Trojan */
- X strcpy (matches, "\\1.*\\2");
- X if (re_strcmp ("\\[|\\]", matches2, NULL) > 0) /* Trojan */
- X strcpy (matches2, "\\1");
- X rewind (subscribers);
- X while (!feof (subscribers)) {
- X address [0] = RESET (_line);
- X fgets (_line, 1023, subscribers);
- X sscanf (_line, "%s", address);
- X upcase (_line);
- X upcase (address);
- X strcpy (address_copy, address);
- X escape_re (address);
- X if (strcmp (matches, ".*") &&
- X# if (ERROR_MAIL_ANALYSIS == 9)
- X strcmp (matches, ".*\\1") &&
- X# endif
- X strcmp (matches, "\\1.*\\2"))
- X sprintf (_address, "^[ \t]*%s", matches +
- X (!strncmp (matches, ".*", 2) ? 2 : 0));
- X else
- X strcpy (_address, address),
- X strcpy (_line, line);
- X if (address [0] != EOS && re_strcmp (_address, _line, NULL) > 0) {
- X /* User found; remove him */
- X char _address [MAX_LINE];
- X BOOLEAN removed = FALSE;
- X
- X fclose (subscribers);
- X sprintf (_address, "^[\t ]*%s ", address);
- X if (cp (subscribersf, OLD_SUBSCRIBERS))
- X gexit (16);
- X REMOVE_ADDRESS (_address, OLD_SUBSCRIBERS, NEW_SUBSCRIBERS,
- X removed_usersf);
- X# ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X# elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X# endif
- X if (mv (NEW_SUBSCRIBERS, subscribersf))
- X gexit (16);
- X# ifdef bsd
- X sigsetmask (sig_mask);
- X# elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X# endif
- X OPEN_FILE (subscribers, subscribersf, "r", "process_message");
- X if (cp (aliasesf, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (_address, OLD_ALIASES, NEW_ALIASES,
- X removed_aliasesf);
- X# ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X# elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X# endif
- X if (mv (NEW_ALIASES, aliasesf))
- X gexit (16);
- X# ifdef bsd
- X sigsetmask (sig_mask);
- X# elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X# endif
- X if (cp (ALIASESF, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (_address, OLD_ALIASES, NEW_ALIASES, "/dev/null");
- X# ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X# elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X# endif
- X if (mv (NEW_ALIASES, ALIASESF))
- X gexit (16);
- X# ifdef bsd
- X sigsetmask (sig_mask);
- X# elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X# endif
- X sprintf (_address, " %s[\t ]*$", address);
- X if (cp (aliasesf, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (_address, OLD_ALIASES, NEW_ALIASES,
- X removed_aliasesf);
- X# ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X# elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X# endif
- X if (mv (NEW_ALIASES, aliasesf))
- X gexit (16);
- X# ifdef bsd
- X sigsetmask (sig_mask);
- X# elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X# endif
- X if (cp (ALIASESF, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (_address, OLD_ALIASES, NEW_ALIASES, "/dev/null");
- X# ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X# elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X# endif
- X if (mv (NEW_ALIASES, ALIASESF))
- X gexit (16);
- X# ifdef bsd
- X sigsetmask (sig_mask);
- X# elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X# endif
- X unlink (OLD_SUBSCRIBERS);
- X unlink (OLD_ALIASES);
- X if (removed)
- X fprintf (forwardmail, "Automatic removal: user %s\n\
- X (possibly mentioned below) will be removed from the system files.\n", address);
- X else {
- X fprintf (forwardmail, "Automatic removal of user %s\n failed.\n",
- X address_copy);
- X break;
- X }
- X }
- X }
- X }
- X
- X strcpy (matches, ".*\\1");
- X if (re_strcmp (warnings, line, matches) > 0) {
- X FILE *inerrors, *outerrors;
- X BOOLEAN found = FALSE;
- X char _line [1024], address [MAX_LINE], _address [MAX_LINE], *sp;
- X long int stime;
- X
- X mv (errorsf, errors2f);
- X inerrors = fopen (errors2f, "r");
- X OPEN_FILE (outerrors, errorsf, "w", "process_message");
- X while (inerrors && !feof (inerrors)) {
- X RESET (_line);
- X fgets (_line, 1023, inerrors);
- X sscanf (_line, "%ld", &stime);
- X if ((sp = strchr (_line, ' ')))
- X ++sp;
- X else
- X sp = _line;
- X upcase (sp);
- X if (!strcmp (line, sp)) { /* Match */
- X found = TRUE;
- X if ((long int) time (0) < (long int) (stime + GRACE_PERIOD))
- X /* No action */
- X fputs (_line, outerrors);
- X else { /* Look for matches in the subscribers file and */
- X char mode [MAX_LINE], address_copy [MAX_LINE], *p;
- X
- X rewind (subscribers); /* change mail mode to POSTPONE */
- X while (!feof (subscribers)) {
- X mode [0] = address [0] = RESET (_line);
- X fgets (_line, 1023, subscribers);
- X sscanf (_line, "%s %s", address, mode);
- X if (!strcmp (mode, POSTPONE))
- X continue;
- X upcase (_line);
- X upcase (address);
- X strcpy (address_copy, address);
- X escape_re (address);
- X# if (ERROR_MAIL_ANALYSIS == 9)
- X if (strcmp (matches, ".*") && strcmp (matches, ".*\\1"))
- X sprintf (_address, "^[ \t]*%s", matches + 2);
- X else
- X# endif
- X strcpy (_address, address),
- X strcpy (_line, line);
- X if (p = strchr (_address, '<'))
- X sprintf (p, "%s", p + 1); /* Remove '<' */
- X if (p = strchr (_address, '>'))
- X sprintf (p, "%s", p + 1); /* Remove '>' */
- X if (address [0] != EOS && re_strcmp (_address, _line, NULL) >
- X 0) {
- X /* User found; change mode */
- X char _address [MAX_LINE];
- X BOOLEAN suspended = FALSE;
- X
- X fclose (subscribers);
- X sprintf (_address, "^[\t ]*%s ", address);
- X if (cp (subscribersf, OLD_SUBSCRIBERS))
- X gexit (16);
- X SUSPEND_ADDRESS (_address, OLD_SUBSCRIBERS, NEW_SUBSCRIBERS);
- X# ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X# elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X# endif
- X if (mv (NEW_SUBSCRIBERS, subscribersf))
- X gexit (16);
- X# ifdef bsd
- X sigsetmask (sig_mask);
- X# elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X# endif
- X OPEN_FILE (subscribers, subscribersf, "r", "process_message");
- X if (suspended)
- X fprintf (forwardmail, "Subscription subspension: user \
- X%s\n (possibly mentioned below) will have his mail mode reset to POSTPONE.\n",
- X address_copy);
- X else {
- X fprintf (forwardmail, "Attempt to suspend subscription \
- Xof user %s\n failed.\n", address_copy);
- X break;
- X }
- X }
- X }
- X }
- X }
- X else if ((long int) time (0) < (long int) (stime + ONE_MONTH))
- X /* discard if older > 1 mo */
- X fputs (_line, outerrors); /* No match; copy error line as is */
- X }
- X if (!found) /* Save new error message */
- X fprintf (outerrors, "%ld %s", time (0), line),
- X fprintf (forwardmail, "Recorded new error message: %s", line);
- X fclose (outerrors);
- X if (inerrors)
- X fclose (inerrors);
- X unlink (errors2f);
- X }
- X }
- X }
- X#endif
- X
- X fprintf (forwardmail, "-----------------------------------------------\
- X--------------------------------\n");
- X rewind (msg);
- X while (!feof (msg)) /* Copy actual message */
- X RESET (line),
- X fgets (line, MAX_LINE - 2, msg),
- X fprintf (forwardmail, "%s", line);
- X COMPLETE_TELNET (forwardmail);
- X fclose (forwardmail);
- X fclose (msg);
- X /* Form sendmail command */
- X if (sender_subscribed != PEER && sender_subscribed != NEWS)
- X if (sys.options & USE_SYSMAIL)
- X sysmail (mailforwardf);
- X else
- X syscom ("%s '%s' < %s", sys.mail.method,
- X (((sys.options & USE_TELNET) == 0) ?
- X ((mailer_daemon || susp_subject || errors_to_owner) ?
- X sys.lists[listid].owner : locase (sender)) : ""),
- X mailforwardf);
- X return;
- X }
- X if (is_moderated) /* USER CONTRIBUTED CODE: Warren Burstein */
- X if (owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
- X /*
- X Sender is owner, look for MESSAGE SEPARATOR, subject and sender,
- X and blank lines and set lines_to_skip (# of lines till
- X MESSAGE_SEPARATOR + one for Subject: + one for Sender: + blank lines)
- X */
- X FILE *msg;
- X long int line_no = 0;
- X
- X OPEN_FILE (msg, msgf, "r", "process_message");
- X while (!feof (msg)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, msg);
- X if (line [0] != EOS && line [strlen (line) - 1] == '\n')
- X line [strlen (line) - 1] = EOS;
- X line_no++;
- X
- X if (!strcmp (line, MESSAGE_SEPARATOR)) {
- X lines_to_skip = line_no;
- X break;
- X }
- X }
- X
- X if (lines_to_skip) {
- X /* Look for Subject: and Sender:, skip blank lines */
- X char match [MAX_LINE];
- X while (!feof (msg)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, msg);
- X if (line [0] != EOS && line [strlen (line) - 1] == '\n')
- X line [strlen (line) - 1] = EOS;
- X
- X strcpy (match, "\\1");
- X if (re_strcmp (SUBJECT, line, match) > 0)
- X strcpy (senders_subject, line + strlen (match)),
- X strcpy (subject_copy, senders_subject),
- X lines_to_skip++;
- X else if (re_strcmp (SENDER, line, match) > 0)
- X strcpy (original_sender, line + strlen (match)),
- X lines_to_skip++;
- X else if (line[0] == EOS) {
- X lines_to_skip++; /* [Tasos: ???] */
- X break;
- X }
- X else
- X break;
- X }
- X while (!feof (msg)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, msg);
- X if (strcmp (line, "\n"))
- X break;
- X lines_to_skip++;
- X }
- X }
- X
- X fclose (msg);
- X }
- X else { /* Sender isn't owner, send message to owner */
- X int i;
- X
- X report_progress (report, tsprintf ("Public message #%04d. Forwarding to \
- Xmoderator", ++public_msg), TRUE);
- X OPEN_FILE (msg_no, msg_nof, "w", "process_message");
- X fprintf (msg_no, "%d %d\n", public_msg, returned_msg);
- X fclose (msg_no);
- X
- X create_header (&forwardmail, mailforwardf, original_sender,
- X originator, sys.lists[listid].owner, senders_subject,
- X FALSE, TRUE, FALSE);
- X
- X sprintf (line, "This message was submitted by %s to list %s.",
- X original_sender, sys.lists[listid].address);
- X fill_text (forwardmail, line);
- X for (i = 0; msgs[i]; i++)
- X fill_text (forwardmail, msgs[i]);
- X fprintf (forwardmail, "%s\n", MESSAGE_SEPARATOR);
- X
- X /* Send these two under the line for extraction when the moderator
- X forwards the message back */
- X fprintf (forwardmail, "Sender: %s\nSubject: %s\n\n",
- X original_sender, senders_subject);
- X if (copy_msg (forwardmail, msgf, FALSE, original_sender, 0, TRUE, FALSE))
- X sendmail (sys.lists[listid].owner, FALSE, FALSE, 0, 0, mailforwardf);
- X already_sent = message_forwarded = TRUE;
- X }
- X fclose (msg);
- X
- X if (!already_sent) {
- X report_progress (report,
- X tsprintf ("Public message #%04d%s. Distributing to all \
- Xsubscribers%s.\n%s",
- X ++public_msg,
- X (sender_subscribed == NEWS ? " (news)" :
- X (sender_subscribed == PEER ? " (peer)" : "")),
- X (sender_subscribed == SUBSCRIBED ?
- X ", news groups and peers" :
- X (sender_subscribed == NEWS ? ", peers" :
- X ", news groups")),
- X sender), TRUE);
- X if (fake_mail && at)
- X report_progress (report,
- X tsprintf ("*** Possible fake mail: Host %s in user \
- Xaddress does\nnot match any of the domains in the Received: header lines.\n",
- X at + 1), FALSE);
- X OPEN_FILE (msg_no, msg_nof, "w", "process_message");
- X fprintf (msg_no, "%d %d\n", public_msg, returned_msg);
- X fclose (msg_no);
- X distributions (sender_subscribed, headerf, msgf, FALSE, sender,
- X original_sender, senders_subject, subject_copy, originator,
- X lines_to_skip, is_moderated);
- X
- X if (append_to_digest && !message_rejected) {
- X long int line_no = 0, digest_toc_lines, digest_lines, total;
- X FILE *fp, *msg;
- X
- X OPEN_FILE (fp, digest_tocf, "a", "process_message");
- X fprintf (fp, "%s\n%s\n", senders_subject, original_sender);
- X fclose (fp);
- X
- X OPEN_FILE (fp, digest_msgf, "a", "process_message");
- X fprintf (fp, "\n");
- X if (sent_date[0] != EOS)
- X fprintf (fp, "Date: %s\n", sent_date);
- X if (original_sender[0] != EOS)
- X fprintf (fp, "From: %s\n", original_sender);
- X if (recipients[0] != EOS)
- X fprintf (fp, "To: %s\n", recipients);
- X if (ccrecipients[0] != EOS)
- X fprintf (fp, "Cc: %s\n", ccrecipients);
- X if (senders_subject[0] != EOS)
- X fprintf (fp, "Subject: %s\n", senders_subject);
- X if (message_id[0] != EOS)
- X fprintf (fp, "Message-ID: %s\n", message_id);
- X if (keywords[0] != EOS)
- X fprintf (fp, "Keywords: %s\n", keywords);
- X fprintf (fp, "\n");
- X
- X OPEN_FILE (msg, msgf, "r", "process_message");
- X while (!feof (msg)) { /* Copy actual message */
- X RESET (line);
- X fgets (line, MAX_LINE - 2, msg);
- X line_no++;
- X
- X if (line_no > lines_to_skip)
- X fprintf (fp, "%s", line);
- X }
- X fclose(msg);
- X
- X fprintf (fp, "\n------------------------------\n");
- X fclose(fp);
- X
- X digest_toc_lines = count_lines_in_file (fp = fopen (digest_tocf, "r"));
- X if (fp) fclose(fp);
- X digest_lines = count_lines_in_file (fp = fopen (digest_msgf, "r"));
- X if (fp) fclose(fp);
- X
- X report_progress (report, tsprintf ("Adding to digest, which now has \
- X%d token + %d message = %d lines",
- X digest_toc_lines, digest_lines,
- X (total = digest_toc_lines + digest_lines)), TRUE);
- X
- X if (total >= sys.lists[listid].digest_lines) { /* Max lines exceeded */
- X BOOLEAN fd = force_digest;
- X
- X force_digest = TRUE;
- X digest_make (TRUE);
- X digest_distribute ();
- X force_digest = fd;
- X }
- X }
- X }
- X
- X update_unprocessed_messages (unprocessed_messages);
- X unlink (unprocessed_tmp);
- X
- X if (!message_rejected && !message_forwarded) { /* New message is archived */
- X cat_append (headerf, archivef);
- X OPEN_FILE (in, msgf, "r", "process_message");
- X OPEN_FILE (out, archivef, "a", "process_message");
- X if (is_moderated) { /* Skip message lines before appending */
- X long int offset = ftell (in); /* Store current position */
- X while (!feof (in)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, in);
- X if (line [0] != EOS && line [strlen (line) - 1] == '\n')
- X line [strlen (line) - 1] = EOS;
- X if (!strcmp (line, MESSAGE_SEPARATOR))
- X break;
- X }
- X if (feof (in)) /* No message separator, so archive the whole msg */
- X (void) fseek (in, offset, SEEK_SET);
- X }
- X while (!feof (in))
- X RESET (line),
- X fgets (line, MAX_LINE - 2, in),
- X fputs (line, out);
- X fclose (in);
- X fclose (out);
- X unlink (headerf);
- X if (is_moderated) /* Save the original author's address */
- X extract_address (original_sender),
- X upcase (original_sender),
- X fprintf (headers, "%s\n", original_sender);
- X else
- X fprintf (headers, "%s\n", sender);
- X fflush (headers);
- X }
- X
- X if (message_id[0] != EOS && !message_rejected && !message_forwarded) {
- X if ((message_ids = fopen (message_idsf, "a")) == NULL)
- X report_progress (report,
- X tsprintf ("\nprocess_message(): Could not open %s",
- X message_idsf), TRUE),
- X gexit (1);
- X fprintf (message_ids, "%s %s\n", message_id, sender); /* Save new id */
- X fclose (message_ids);
- X }
- X if (sum[0] != EOS && !message_rejected && !message_forwarded)
- X if ((message_ids = fopen (checksumsf, "a")))
- X fprintf (message_ids, "%s %s\n", sum, sender),
- X fclose (message_ids);
- X}
- X
- X/*
- X Check to see if there are subscribers/newsgroups/peers that did not
- X receive any mail because of a previous interrupted distribution.
- X*/
- X
- XBOOLEAN unprocessed_users (char *unprocessed, char *s, FILE *report)
- X{
- X struct stat stat_buf;
- X
- X if (!stat (unprocessed, &stat_buf)) { /* There is undelivered mail */
- X if (stat_buf.st_size > 0)
- X report_progress (report,
- X tsprintf ("Resuming delivery of interrupted mail to %s",
- X s), TRUE);
- X return TRUE;
- X }
- X return FALSE;
- X}
- X
- X/*
- X Distribute a message, either to regular subscribers, or to DIGEST
- X subscribers if is_digest is TRUE.
- X Write an archive file if is_digest == sys.lists[listid].options & ARCHIVE_DIGEST
- X*/
- X
- Xvoid distributions (BOOLEAN subscribed, char *header_file,
- X char *message_file, BOOLEAN is_digest,
- X char *sender, char *original_sender, char *senders_subject,
- X char *subject_copy, char *originator,
- X long int lines_to_skip, BOOLEAN is_moderated)
- X{
- X BOOLEAN sremnants, nremnants, premnants, success;
- X
- X if (!(sremnants = unprocessed_users (unprocessed_subscribersf,
- X "subscribers", report)))
- X echo ("0", unprocessed_subscribersf);
- X if (!(nremnants = unprocessed_users (unprocessed_newsf, "news", report)))
- X echo ("0", unprocessed_newsf);
- X if (!(premnants = unprocessed_users (unprocessed_peersf, "peers", report)))
- X echo ("0", unprocessed_peersf);
- X
- X success = do_distribute (message_file, subscribers, subscribersf, sremnants,
- X unprocessed_subscribersf, send_to_subscribers,
- X sender, original_sender, senders_subject,
- X subject_copy, originator, report, FALSE,
- X multi_recip, lines_to_skip, is_digest, TRUE,
- X subscribed, !is_digest);
- X unlink (unprocessed_subscribersf);
- X
- X if ((subscribed == SUBSCRIBED || subscribed == PEER) && !is_digest && success)
- X /* Send to news also */
- X success &= do_distribute (message_file, news, newsf, nremnants,
- X unprocessed_newsf, TRUE, sender, original_sender,
- X senders_subject, subject_copy, originator, report,
- X TRUE, FALSE, lines_to_skip, is_digest, FALSE,
- X subscribed, FALSE);
- X unlink (unprocessed_newsf);
- X
- X if ((subscribed == SUBSCRIBED || subscribed == NEWS) && !is_digest && success)
- X /* Send to peers also */
- X success &= do_distribute (message_file, peers, peersf, premnants,
- X unprocessed_peersf, TRUE, sender, original_sender,
- X senders_subject, subject_copy, originator,
- X report, FALSE, FALSE, lines_to_skip, is_digest,
- X FALSE, subscribed, FALSE);
- X unlink (unprocessed_peersf);
- X
- X if (success &&
- X (((sys.lists[listid].options & ARCHIVE_LIST) &&
- X !(sys.lists[listid].options & ARCHIVE_DIGEST) && !is_digest) ||
- X (is_digest & sys.lists[listid].options & ARCHIVE_DIGEST))) {
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("distributions", SEM_ARCHIVES);
- X#endif
- X do_archive (header_file, message_file, subject_copy, is_moderated);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("distributions", SEM_ARCHIVES);
- X#endif
- X }
- X}
- X
- X/*
- X Do the distribution of the message to the specified list of subscribers.
- X The BOOLEAN argument 'posting' should be TRUE when posting AND gating to
- X news, and FALSE otherwise.
- X
- X Undelivered mail has higher priority.
- X*/
- X
- XBOOLEAN do_distribute (char *message_file,
- X FILE *recipient_list, char *file, BOOLEAN mail_remnants,
- X char *unprocessed, BOOLEAN send_to_subscribers,
- X char *sender, char *original_sender, char *senders_subject,
- X char *subject_copy, char *originator, FILE *report,
- X BOOLEAN posting, BOOLEAN multi_recip,
- X long int lines_to_skip, BOOLEAN is_digest,
- X BOOLEAN is_subscribers, BOOLEAN subscribed,
- X BOOLEAN check_size)
- X{
- X char name [MAX_LINE]; /* holds each subscribers name */
- X char mailmode [MAX_LINE]; /* send message back to sender or not */
- X char subscriber [MAX_LINE]; /* holds each subscriber's address */
- X char recipient_file [MAX_LINE]; /* file of subscribers to use when -r */
- X char restricted_subscriber [MAX_LINE]; /* name of subscriber in RESTRICTED */
- X char line [MAX_LINE];
- X FILE *forwardmail, *f;
- X BOOLEAN alternate_file = FALSE;
- X int nrecipients = 0, offset = -1;
- X
- X /* Check if there is previously undelivered mail */
- X if (mail_remnants) { /* There is undelivered mail; move to offset */
- X OPEN_FILE (f, unprocessed, "r", "do_distribute");
- X fscanf (f, "%d", &offset);
- X fclose (f);
- X if (offset < 0) /* Empty unprocessed file, go to eof */
- X while (!feof (recipient_list))
- X fgets (line, MAX_LINE - 2, recipient_list);
- X else /* Skip 'offset' subscribers, check for DIGEST subscribers */
- X while (!feof (recipient_list) && offset) {
- X if (!is_digest &&
- X read_recipient (recipient_list, subscriber, mailmode, name,
- X is_subscribers) && !strcmp (mailmode, DIGEST))
- X append_to_digest = TRUE;
- X --offset;
- X }
- X }
- X else {
- X if (!send_to_subscribers) { /* -r: Check if restricted mail has arrived */
- X rewind (restricted);
- X while (!feof (restricted)) {
- X alternate_file = TRUE;
- X restricted_subscriber[0] = RESET (recipient_file);
- X fscanf (restricted, "%s %s", restricted_subscriber, recipient_file);
- X upcase (restricted_subscriber);
- X if (!strcmp (restricted_subscriber, sender)) {
- X if (!strcmp (recipient_file, NO_RECIPIENT_FILE)) {
- X /* Do not forward to anyone */
- X report_progress (report, "No alternate recipient file specified. \
- XMessage ignored.\n", FALSE);
- X return FALSE;
- X }
- X /* Restricted mail; forward message only to the people listed
- X in recipient_file */
- X OPEN_FILE (recipient_list, recipient_file, "r", "do_distribute");
- X report_progress (report, tsprintf ("Restricted mail. Distributing \
- Xonly to individuals listed in %s", recipient_file), TRUE);
- X break;
- X }
- X }
- X }
- X }
- X if (!mail_remnants)
- X rewind (recipient_list);
- X while (!feof (recipient_list)) { /* Send to all of them */
- X
- X if (!read_recipient (recipient_list, subscriber, mailmode, name,
- X is_subscribers))
- X continue;
- X
- X if (is_digest) {
- X if (strcmp (mailmode, DIGEST))
- X continue;
- X }
- X else if (!strcmp (mailmode, DIGEST)) {
- X append_to_digest = TRUE;
- X continue;
- X }
- X else if (!strcmp (mailmode, NOACK)) {
- X upcase (subscriber);
- X if (!strcmp (subscriber, sender) || !strcmp (subscriber, originator))
- X continue;
- X }
- X else if (!strcmp (mailmode, POSTPONE)) /* No email to this subscriber */
- X continue;
- X else if (mailmode[0] != EOS && strcmp (mailmode, ACK)) {
- X syscom ("echo Unrecognized mail mode %s for recipient %s in %s | \
- X%s %s %s",
- X mailmode, subscriber, file, UCB_MAIL, sys.manager,
- X sys.lists[listid].owner);
- X report_progress (report, tsprintf ("\ndo_distribute(): Unrecognized mail \
- Xmode %s in %s", mailmode, file), TRUE);
- X continue;
- X }
- X RESET (senders_subject);
- X strcpy (senders_subject, subject_copy);
- X if (multi_recip) {
- X if ((multi_recipients[nrecipients] =
- X (char *) malloc ((strlen (subscriber) + 1) * sizeof (char)))
- X == NULL)
- X report_progress (report, "\ndo_distribute(): malloc() failed", TRUE),
- X gexit (11);
- X strcpy (multi_recipients[nrecipients++], locase (subscriber));
- X }
- X /* Prepare header */
- X if (posting) {
- X if (sys.options & POST_MAIL) /* Post to news group */
- X create_news_header (&forwardmail, mailforwardf, original_sender,
- X originator, name, senders_subject);
- X else if (sys.options & GATE_MAIL) /* Gate to news gateway */
- X create_gate_header (&forwardmail, mailforwardf, original_sender,
- X originator, subscriber, name, senders_subject),
- X posting = FALSE;
- X if (!copy_msg (forwardmail, message_file, posting, original_sender,
- X lines_to_skip, subscribed, check_size))
- X return FALSE;
- X }
- X else { /* Regular mail */
- X if (multi_recip) { /* Multi recipient header */
- X if (nrecipients == maxrecipients) {
- X create_multi_recipient_header (&forwardmail, mailforwardf,
- X original_sender, originator,
- X tsprintf ("Multiple recipients of \
- Xlist <%s>", sys.lists[listid].address),
- X senders_subject, nrecipients);
- X if (!copy_msg (forwardmail, message_file, posting, original_sender,
- X lines_to_skip, subscribed, check_size))
- X return FALSE;
- X }
- X }
- X else { /* Single recipient header */
- X create_header (&forwardmail, mailforwardf, original_sender, originator,
- X subscriber, senders_subject, FALSE, FALSE, FALSE);
- X if (!copy_msg (forwardmail, message_file, posting, original_sender,
- X lines_to_skip, subscribed, check_size))
- X return FALSE;
- X }
- X }
- X if (sendmail (subscriber, posting, multi_recip, nrecipients, maxrecipients,
- X mailforwardf))
- X update_unprocessed (unprocessed, posting, multi_recip, nrecipients);
- X if (nrecipients == maxrecipients)
- X nrecipients = 0;
- X }
- X if (alternate_file) /* Close alternate recipient file */
- X fclose (recipient_list);
- X
- X if (multi_recip && (nrecipients != 0)) { /* Left overs */
- X create_multi_recipient_header (&forwardmail, mailforwardf,
- X original_sender, originator,
- X tsprintf ("Multiple recipients of list <%s>",
- X sys.lists[listid].address),
- X senders_subject, nrecipients);
- X if (copy_msg (forwardmail, message_file, posting, original_sender,
- X lines_to_skip, subscribed, check_size))
- X sendmail (subscriber, posting, multi_recip, nrecipients, nrecipients,
- X mailforwardf),
- X update_unprocessed (unprocessed, posting, multi_recip, nrecipients);
- X else
- X return FALSE;
- X }
- X return TRUE;
- X}
- X
- X/*
- X Increment count of number of recipients that have received the current
- X message.
- X*/
- X
- Xvoid update_unprocessed (char *unprocessed, BOOLEAN posting,
- X BOOLEAN multi_recip, int nrecipients)
- X{
- X int nproc = 1, offset;
- X FILE *f;
- X struct stat stat_buf;
- X
- X if (stat (unprocessed, &stat_buf) || stat_buf.st_size <= 0)
- X return;
- X if (multi_recip && !posting)
- X nproc = nrecipients;
- X OPEN_FILE (f, unprocessed, "r", "update_unprocessed");
- X fscanf (f, "%d", &offset);
- X fclose (f);
- X OPEN_FILE (f, unprocessed, "w", "update_unprocessed");
- X fprintf (f, "%d\n", offset + nproc);
- X fclose (f);
- X}
- X
- X/*
- X Remove the message that was just delivered to everybody from the
- X unprocessed file.
- X*/
- X
- Xvoid update_unprocessed_messages (char *unprocessed)
- X{
- X FILE *in, *out;
- X char line [MAX_LINE];
- X
- X OPEN_FILE (in, unprocessed, "r", "update_unprocessed_messages");
- X OPEN_FILE (out, unprocessed_tmp, "w", "update_unprocessed_messages");
- X if (!feof (in))
- X fgets (line, MAX_LINE - 2, in); /* Skip first "From " */
- X RESET (line);
- X while (!feof (in) &&
- X (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE))))
- X fgets (line, MAX_LINE - 2, in);
- X while (!feof (in)) /* Copy rest of messages */
- X fputs (line, out),
- X RESET (line),
- X fgets (line, MAX_LINE - 2, in);
- X fclose (in);
- X fclose (out);
- X mv (unprocessed_tmp, unprocessed);
- X}
- X
- X/*
- X Copy the original message from message_file to the outgoing message.
- X Skip first "skip" lines. Reject it if it messages have a certain
- X limit, and that limit is exceeded (only when not distributing a digest).
- X*/
- X
- XBOOLEAN copy_msg (FILE *forwardmail, char *message_file, BOOLEAN posting,
- X char *sender, long int lines_to_skip, BOOLEAN subscribed,
- X BOOLEAN check_size)
- X{
- X FILE *msg;
- X char line [MAX_LINE];
- X char original_sender [MAX_LINE];
- X long int count = 0, line_no = 0;
- X
- X OPEN_FILE (msg, message_file, "r", "copy_msg");
- X while (!feof (msg)) { /* Copy actual message */
- X RESET (line);
- X fgets (line, MAX_LINE - 2, msg);
- X line_no++;
- X
- X if (line_no > lines_to_skip)
- X fprintf (forwardmail, "%s", line);
- X
- X count += strlen (line);
- X message_rejected = FALSE;
- X if (check_size &&
- X (sys.options & LIMIT_MSG) && (count > sys.limits.msg) &&
- X subscribed != FALSE && subscribed != PEER && subscribed != NEWS) {
- X fclose (forwardmail);
- X rewind (msg);
- X strcpy (original_sender, sender);
- X extract_address (original_sender);
- X create_header (&forwardmail, mailforwardf, sys.lists[listid].address,
- X sys.lists[listid].address, original_sender,
- X "Posting rejected", COPY_OWNER (ccerrors), FALSE, TRUE);
- X fprintf (forwardmail, "Your posting to list %s was rejected.\n\
- XReason: message size limit exceeded (maximum allowed: %ld bytes)\n\
- XThe first few lines of your message are included herein for reference:\n\n",
- X sys.lists[listid].alias, sys.limits.msg);
- X report_progress (report, "Message rejected: maximum size exceeded",
- X TRUE);
- X message_rejected = TRUE;
- X count = 0;
- X while (!feof (msg) && count < 10)
- X RESET (line),
- X fgets (line, MAX_LINE - 2, msg),
- X fprintf (forwardmail, "%s", line),
- X ++count;
- X COMPLETE_TELNET (forwardmail);
- X fclose (forwardmail);
- X fclose (msg);
- X sendmail (sender, FALSE, FALSE, 0, 0, mailforwardf);
- X return FALSE;
- X }
- X }
- X if (!posting && (sys.options & USE_TELNET))
- X COMPLETE_FILE (forwardmail);
- X fclose (forwardmail);
- X fclose (msg);
- X return TRUE;
- X}
- X
- X/*
- X Send email (to subscribers/news/gateways/peers). It may send one single
- X copy to one recipient, or one copy to multiple recipients.
- X*/
- X
- XBOOLEAN sendmail (char *subscriber, BOOLEAN posting, BOOLEAN multi_recip,
- X int nrecipients, int maxrecipients, char *mailforwardf)
- X{
- X char *buf;
- X int size, i;
- X
- X /* Form sendmail command */
- X if (posting && (sys.options & POST_MAIL)) { /* Post to news */
- X if (syscom ("%s -h < %s > %s 2> %s", INEWS, mailforwardf, INEWS_REPLY,
- X INEWS_REPLY)) {
- X FILE *f = fopen (mailforwardf, "r");
- X char line [MAX_LINE], match [MAX_LINE];
- X while (f && !feof (f)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, f);
- X strcpy (match, "\\1");
- X if (re_strcmp (FROM, line, match) > 0) {
- X sprintf (line, "%s", line + strlen (match)); /* Save From: */
- X line [strlen (line) - 1] = EOS; /* \n -> \0 */
- X extract_address (line);
- X break;
- X }
- X }
- X if (f)
- X fclose (f);
- X syscom ("%s -s \"Posting to `grep '^Newsgroups:' %s | \
- Xawk '{ print $2 }'` failed: \" %s %s < %s",
- X UCB_MAIL, mailforwardf, line, sys.lists[listid].owner,
- X INEWS_REPLY);
- X unlink (INEWS_REPLY);
- X }
- X }
- X else { /* Send email */
- X if (multi_recip) {
- X if (nrecipients == maxrecipients) {
- X if ((sys.options & USE_TELNET) == 0) { /* Line up recipients */
- X size = strlen (sys.mail.method) + strlen (multi_recipients[0]) +
- X strlen (mailforwardf) + 1 + 1;
- X if ((buf = (char *) malloc (size * sizeof (char))) == NULL)
- X report_progress (report, "\nsendmail(): malloc() failed", TRUE),
- X gexit (11);
- X sprintf (buf, "%s %s", sys.mail.method, multi_recipients[0]);
- X for (i = 1; i < nrecipients; i++)
- X size += strlen (multi_recipients[i]) + 2,
- X buf = (char *) realloc (buf, size * sizeof (char)),
- X sprintf (buf + strlen (buf), " %s", multi_recipients[i]);
- X if ((int) strlen (buf) > SHELL_CHAR_LIMIT)
- X report_progress (report,
- X tsprintf ("Too many multiple \
- Xrecipients: buffer limit (%d) exceeded by %d characters:\n%s",
- X SHELL_CHAR_LIMIT, strlen (buf) -
- X SHELL_CHAR_LIMIT, buf), TRUE),
- X gexit (9);
- X syscom ("%s < %s", buf, mailforwardf);
- X free ((char *) buf);
- X }
- X else if (sys.options & USE_SYSMAIL)
- X sysmail (mailforwardf);
- X else /* telnet */
- X syscom ("%s < %s", sys.mail.method, mailforwardf);
- X return TRUE;
- X }
- X }
- X else /* Single recipient */
- X if (sys.options & USE_SYSMAIL)
- X sysmail (mailforwardf);
- X else
- X extract_address (locase (subscriber)),
- X syscom ("%s '%s' < %s", sys.mail.method,
- X (((sys.options & USE_TELNET) == 0) ? subscriber : ""),
- X mailforwardf);
- X return TRUE;
- X }
- X return FALSE;
- X}
- X
- Xvoid usage ()
- X{
- X fprintf (stderr, "Usage: list <-L LIST_ALIAS> [-r] [-m #] [-1] [-f] [-e] \
- X[-s] [-p] [-P] [-v] [-M] [-d] [-i address] [-Z] [-D]\n\
- X-L: Process LIST_ALIAS (LIST_ALIAS has to be all in capital letters).\n\
- X-r: Restricted mail.\n\
- X-m: Specify number of multiple recipients in one outgoing message.\n\
- X-1: Execute only once.\n\
- X-f: Forward rejected messages to the list's owner.\n\
- X-e: Echo reports to the screen.\n\
- X-s: Do not check for subscriptions.\n\
- X-p: Replies to posted (to news) messages will go to the author.\n\
- X-P: Replies to distributed messages will go to the author.\n\
- X-v: Version number.\n\
- X-M: Moderated list.\n\
- X-d: Distribute digest.\n\
- X-i: Send partial digest to 'address'.\n\
- X-Z: Turn off automatic compression of archived messages.\n\
- X-D: Turn debug on.\n");
- X exit (3);
- X}
- X
- Xvoid list_config (char *alias)
- X{
- X if (!alias)
- X return;
- X setup_string (subscribersf, alias, SUBSCRIBERS);
- X setup_string (headersf, alias, HEADERS);
- X setup_string (restrictedf, alias, RESTRICTED);
- X setup_string (newsf, alias, NEWSF);
- X setup_string (peersf, alias, PEERS);
- X setup_string (aliasesf, alias, ALIASES);
- X setup_string (ignoredf, alias, IGNORED);
- X setup_string (list_mail_f, alias, LIST_MAIL_FILE);
- X setup_string (list_moderated_f, alias, LIST_MODERATED_F);
- X setup_string (mboxf, alias, MBOX);
- X setup_string (msg_nof, alias, MSG_NO);
- X setup_string (mailforwardf, alias, MAILFORWARD);
- X setup_string (msgf, alias, MSG);
- X setup_string (archivef, alias, ARCHIVE);
- X setup_string (digest_nof, alias, DIGEST_NO);
- X setup_string (digest_tocf, alias, DIGEST_TOC);
- X setup_string (digest_msgf, alias, DIGEST_MSG);
- X setup_string (digest_timef, alias, DIGEST_TIME);
- X setup_string (headerf, alias, HEADER);
- X setup_string (mail_copyf, alias, MAIL_COPY);
- X setup_string (report_listf, alias, REPORT_LIST);
- X setup_string (message_idsf, alias, MESSAGE_IDS_F);
- X setup_string (unprocessed_digestf, alias, UNPROC_DIGEST);
- X setup_string (unprocessed_subscribersf, alias, UNPROC_SUBSCRIBERS);
- X setup_string (unprocessed_peersf, alias, UNPROC_PEERS);
- X setup_string (unprocessed_newsf, alias, UNPROC_NEWS);
- X setup_string (unprocessed_messages, alias, UNPROC_MESSAGES);
- X setup_string (unprocessed_tmp, alias, UNPROC_TMP);
- X setup_string (removed_usersf, alias, REMOVED_USERS);
- X setup_string (removed_aliasesf, alias, REMOVED_ALIASES);
- X setup_string (limitsf, alias, LIST_LIMITS);
- X setup_string (errorsf, alias, ERRORSF);
- X setup_string (errors2f, alias, ERRORS2F);
- X setup_string (checksumsf, alias, CHECKSUMS);
- X}
- X
- Xvoid version ()
- X{
- X fprintf (stderr, "%s\n", VERSION);
- X exit (0);
- X}
- X
- X/*
- X Graceful exit. Remove pid file.
- X*/
- X
- Xint gexit (int exitcode)
- X{
- X unlink (PID_LIST);
- X#ifdef GO_INTERACTIVE
- X /* Reset flag so that serverd will not wait for ever. */
- X if (sid >= 0 && V (sid, SEM_DLVR_MAIL) < 0)
- X report_progress (report, tsprintf ("\ngexit(): Error V(); errno %d",
- X errno), TRUE);
- X#endif
- X exit (exitcode);
- X}
- X
- X/*
- X Write the text to fp, filling to 80 characters. Writing a null string
- X flushes the paragraph.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- X#define LEN 79 /* to avoid wrapping on some terminals */
- X
- Xvoid fill_text (FILE *fp, char *s)
- X{
- X static char buf [LEN + 1];
- X static int pos = 0;
- X char word [LEN + 1], *p;
- X
- X if (*s == EOS) { /* Flush buffer */
- X if (pos)
- X fprintf (fp, "%s\n", buf),
- X pos = 0;
- X fprintf (fp, "\n");
- X }
- X else
- X while (*s) { /* Get a word */
- X for (p = word; (*s != EOS) && !isspace (*s); s++, p++)
- X *p = *s;
- X *p = EOS;
- X
- X /* Flush line if it won't fit */
- X if ((pos + strlen (word) + (pos != 0)) > LEN)
- X fprintf (fp, "%s\n", buf),
- X pos = 0;
- X
- X /* Add word to line, precede with space if not first word */
- X if (pos)
- X buf[pos++] = ' ';
- X strcpy (&buf[pos], word);
- X pos += (int) strlen (word);
- X buf[pos] = EOS;
- X
- X /* Skip trailing spaces */
- X while (isspace(*s))
- X s++;
- X }
- X}
- X
- X/*
- X Read a line from the recipients file, fill subscriber, mailmode and name.
- X Return TRUE if it's OK, FALSE if no subscriber found.
- X*/
- X
- XBOOLEAN read_recipient (FILE *fp, char *subscriber, char *mailmode, char *name,
- X BOOLEAN is_subscribers)
- X{
- X char othermode [MAX_LINE];
- X int i;
- X FILE *f;
- X
- X othermode[0] = mailmode[0] = name[0] = RESET (subscriber);
- X if (!extract_subscriber (fp, subscriber, FALSE)) {
- X fgets (othermode, MAX_LINE - 2, fp); /* Skip to eoln */
- X NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS(subscriber, "read_recipient", FALSE);
- X return FALSE;
- X }
- X if (subscriber[0] == EOS)
- X return FALSE;
- X fscanf (fp, "%s ", mailmode);
- X
- X if (is_subscribers)
- X for (i = 1; i < (MAX_SET_OPTIONS - 1); i++) /* Skip unused options */
- X fscanf (fp, "%s ", othermode);
- X
- X fgets (name, MAX_LINE - 2, fp);
- X if (name [0] != EOS && name [strlen (name) - 1] == '\n')
- X name [strlen (name) - 1] = EOS;
- X upcase (mailmode);
- X
- X return TRUE;
- X}
- X
- X/*
- X Count the number of lines in a file.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- Xlong int count_lines_in_file (FILE *fp)
- X{
- X long int lines = 0;
- X char line [MAX_LINE];
- X
- X if (fp)
- X while (!feof (fp)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, fp);
- X if (line[0] != EOS)
- X ++lines;
- X }
- X
- X return lines;
- X}
- X
- X/*
- X Put the digest_toc and digest_msg files together to make a digest
- X in unprocessed_digestf.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- Xvoid digest_make (BOOLEAN to_everyone)
- X{
- X FILE *ofp, *ifp;
- X char line1 [MAX_LINE], line2 [MAX_LINE], end_of_digest [MAX_LINE];
- X int i, topics = 0, ntopics = 0;
- X
- X OPEN_FILE (ofp, (to_everyone ? unprocessed_digestf : msgf), "w",
- X "digest_make");
- X fprintf (ofp, "\t\t\t %s\n\nTopics covered in this issue include:\n\n",
- X tsprintf ("%s Digest %d", list_alias, ++digest_msg));
- X
- X OPEN_FILE (ifp, digest_tocf, "r", "digest_make");
- X while (!feof (ifp)) {
- X line1[0] = RESET (line2);
- X fgets (line1, MAX_LINE - 2, ifp);
- X fgets (line2, MAX_LINE - 2, ifp);
- X if (line1[0] != EOS)
- X fprintf (ofp, "%3d) %s\tby %s", ++ntopics, line1, line2);
- X }
- X fclose (ifp);
- X
- X fprintf (ofp, "\n------------------------------------------\
- X----------------------------\n");
- X
- X OPEN_FILE (ifp, digest_msgf, "r", "digest_make");
- X while (!feof (ifp)) {
- X RESET (line1);
- X fgets (line1, MAX_LINE - 2, ifp);
- X if (line1[0] != EOS)
- X fputs (line1, ofp);
- X }
- X fclose (ifp);
- X
- X sprintf (end_of_digest, "\nEnd of %s Digest %d\n", list_alias, digest_msg);
- X fprintf (ofp, "%s", end_of_digest);
- X for (i = 0; i < strlen (end_of_digest) - 2; ++i)
- X fprintf (ofp, "*");
- X fprintf (ofp, "\n");
- X fclose (ofp);
- X
- X if (to_everyone) {
- X unlink (digest_tocf);
- X unlink (digest_msgf);
- X OPEN_FILE (ofp, digest_timef, "w", "digest_make");
- X fprintf (ofp, "%ld\n", time (0));
- X fclose (ofp);
- X }
- X
- X report_progress (report,
- X tsprintf ("%sDistributing %sdigest #%04d.", DIGEST_TIME_,
- X (to_everyone ? "" : "partial "), digest_msg),
- X TRUE);
- X
- X if (to_everyone) {
- X OPEN_FILE (digest_no, digest_nof, "w", "digest_make");
- X fprintf (digest_no, "%d\n", digest_msg);
- X fclose (digest_no);
- X }
- X}
- X
- X/*
- X Distribute a digest.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- Xvoid digest_distribute (void)
- X{
- X char subject1[MAX_LINE], subject2[MAX_LINE];
- X struct stat stat_buf;
- X
- X sprintf (subject1, "%s digest %d", sys.lists[listid].alias, digest_msg);
- X strcpy (subject2, subject1);
- X
- X if (!stat (unprocessed_digestf, &stat_buf) && stat_buf.st_size > 0)
- X distributions (SUBSCRIBED, NULL, unprocessed_digestf, ARCHIVE_DIGEST,
- X sys.lists[listid].address,
- X sys.lists[listid].address, subject1, subject2,
- X sys.lists[listid].address, 0, FALSE);
- X unlink (unprocessed_digestf);
- X}
- X
- X/*
- X Copy message_file to a file in arch_dir, whose name is specified
- X by arch_spec.
- X
- X arch_spec is interpreted like a printf format string. The following
- X formats are recognized:
- X
- X %m month 01 - 12
- X %d day of month 01 - 31
- X %y year 00 - 99
- X %j julian date 001 - 366
- X %h month name Jan - Dec
- X %a contents of Archive-Name header line (cannot be used if arching digests)
- X %# digest number (only use this if archiving digests)
- X %1 first non-blank line of file
- X %v volume number (extracted from Volume # Number # line)
- X %n issue number (extracted from Volume # Number # line)
- X %% the character %
- X any other characters are entered into the name of the file
- X example: arch.%y%m%d
- X
- X If there already is a file by that name, add additional characters
- X to make a unique file.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- Xvoid do_archive (char *header_file, char *message_file, char *subject,
- X BOOLEAN is_moderated)
- X{
- X FILE *fp;
- X char fullpath [MAX_LINE], line [MAX_LINE], dirname [MAX_LINE],
- X report_msg [MAX_LINE], *src, *dst, *p, *filep;
- X int i, volume_num = -1, issue_num = -1;
- X BOOLEAN done_volume = FALSE;
- X#ifdef ultrix
- X time_t time_is = 0;
- X#else
- X long int time_is = 0;
- X#endif
- X struct tm *t;
- X struct stat stat_buf;
- X
- X time (&time_is);
- X t = localtime (&time_is);
- X
- X strcpy (fullpath, sys.lists[listid].arch_dir);
- X dst = fullpath + strlen (fullpath);
- X *dst++ = '/';
- X filep = dst; /* start of file name */
- X
- X for (src = sys.lists[listid].arch_spec; *src != EOS; src++) {
- X if (*src == '%') {
- X /* found a %, if next char is a known format specifier, print the
- X appropriate value. Otherwise just print the character, so %% prints
- X one %. */
- X switch (*++src) {
- X case 'm': /* month number */
- X sprintf (dst, "%02d", t->tm_mon + 1);
- X dst += 2;
- X break;
- X case 'd': /* day of month */
- X sprintf (dst, "%02d", t->tm_mday);
- X dst += 2;
- X break;
- X case 'y': /* 2 digits of year */
- X sprintf (dst, "%02d", t->tm_year % 100);
- X dst += 2;
- X break;
- X case 'j': /* julian date */
- X sprintf (dst, "%03d", t->tm_yday + 1);
- X dst += 3;
- X break;
- X case 'h': /* short name of month */
- X strcpy (dst, mname[t->tm_mon]);
- X dst += 3;
- X break;
- X case 'a': /* contents of Archive-Name: header line */
- X if (archive_name[0] == EOS)
- X if (!get_archive_name (message_file, archive_name)) {
- X reject_archive ("Archive-Name: name missing", subject);
- X return;
- X }
- X strcpy (dst, archive_name);
- X dst += strlen (archive_name);
- X break;
- X case '#': /* digest number */
- X sprintf (dst, "%d", digest_msg);
- X dst += strlen (dst);
- X break;
- X case '1': /* 1st word of 1st nonblank line of message */
- X OPEN_FILE (fp, message_file, "r", "do_archive");
- X while (!feof (fp)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, fp);
- X if (line [0] != EOS && line [strlen (line) - 1] == '\n')
- X line [strlen (line) - 1] = EOS;
- X /* Skip leading blanks, truncate string at blank. */
- X for (p = line; *p && isspace (*p); p++);
- X if (*p) {
- X strcpy (archive_name, p);
- X for (p = archive_name; *p != EOS && !isspace (*p); p++);
- X *p = EOS;
- X break;
- X }
- X locase (archive_name);
- X }
- X fclose (fp);
- X strcpy (dst, archive_name);
- X dst += strlen (archive_name);
- X break;
- X case 'v':
- X if (!done_volume) {
- X if (!get_volume (message_file, &volume_num, &issue_num)) {
- X reject_archive ("Volume number missing", subject);
- X return;
- X }
- X done_volume = TRUE;
- X }
- X sprintf (dst, "%d", volume_num);
- X dst += strlen (dst);
- X break;
- X case 'n':
- X if (!done_volume) {
- X if (!get_volume (message_file, &volume_num, &issue_num)) {
- X reject_archive ("Issue number missing", subject);
- X return;
- X }
- X done_volume = TRUE;
- X }
- X
- X sprintf (dst, "%d", issue_num);
- X dst += strlen(dst);
- X break;
- X default:
- X *dst++ = *src;
- X }
- X }
- X else
- X *dst++ = *src;
- X }
- X *dst = EOS;
- X
- X if (filep == dst) { /* No name to archive */
- X reject_archive ("Archive name is blank", subject);
- X return;
- X }
- X
- X if (re_strcmp ("/*\\.\\./", fullpath, NULL) > 0) {
- X /* Someone is trying to write an archive into a parent dir. */
- X reject_archive (tsprintf ("Archive file %s contains ..", fullpath),
- X subject);
- X return;
- X }
- X if (re_strcmp ("/", archive_name, NULL)) {
- X reject_archive (tsprintf ("Archive file %s contains directory", archive_name),
- X subject);
- X return;
- X }
- X for (i = 0; i < strlen (fullpath); i++)
- X if (!isalnum (fullpath[i]) && fullpath[i] != '.' && fullpath[i] != '/' &&
- X fullpath[i] != '@' && fullpath[i] != '#' && fullpath[i] != '%' &&
- X fullpath[i] != '-' && fullpath[i] != '_') {
- X reject_archive (tsprintf ("Archive file %s contains invalid character '%c'",
- X fullpath, fullpath[i]), subject);
- X return;
- X }
- X
- X /* Create archive dir if needed. Can't use arch_dir, there might be
- X /'s in %1 or %a or arch_spec. */
- X strcpy (dirname, fullpath);
- X if (p = strrchr (dirname, '/'))
- X *p = EOS;
- X if (!mkdir1 (dirname, report_msg, mask)) {
- X reject_archive (report_msg, subject);
- X return;
- X }
- X
- X/*
- X If the file already exists, append .1, .2 and so on.
- X for (i = 1; access (fullpath, 0) == 0; i++)
- X sprintf (dst, ".%d", i);
- X*/
- X
- X report_progress (report, tsprintf ("Archiving in %s", fullpath), TRUE);
- X
- X if (!no_compression &&
- X stat (fullpath, &stat_buf)) /* Compress previous archive files */
- X syscom ("compress %s/* > /dev/null 2>&1 < /dev/null", dirname),
- X syscom ("uncompress %s/%s.Z %s/%s.Z > /dev/null 2>&1 < /dev/null", dirname,
- X DIRF, dirname, INDEX);
- X if (is_moderated) { /* Skip message lines before appending */
- X char line [MAX_LINE];
- X FILE *in, *out;
- X if (header_file)
- X cat_append (header_file, fullpath);
- X OPEN_FILE (in, message_file, "r", "do_archive");
- X OPEN_FILE (out, fullpath, "a", "do_archive");
- X while (!feof (in)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, in);
- X if (line [0] != EOS && line [strlen (line) - 1] == '\n')
- X line [strlen (line) - 1] = EOS;
- X if (!strcmp (line, MESSAGE_SEPARATOR))
- X break;
- X }
- X if (feof (in)) /* No message separator, so archive the whole msg */
- X rewind (in);
- X while (!feof (in))
- X RESET (line),
- X fgets (line, MAX_LINE - 2, in),
- X fputs (line, out);
- X fclose (in);
- X fclose (out);
- X }
- X else {
- X if (header_file)
- X cat_append (header_file, fullpath);
- X cat_append (message_file, fullpath);
- X }
- X chmod (fullpath, 0644 & (0644 ^ otoi (archives_mask)));
- X
- X if (*sys.lists[listid].farch_dir != EOS)
- X farch (sys.lists[listid].arch_dir, sys.lists[listid].farch_dir,
- X sys.lists[listid].arch_pass, fullpath, filep, subject);
- X}
- X
- X/*
- X Add the archive file to the DIR in farch_dir.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- Xvoid farch (char *arch_dir, char *farch_dir, char *password, char *fullpath,
- X char *file_part, char *subject)
- X{
- X FILE *fin, *fout;
- X long int dummy;
- X char dir [MAX_LINE], file [MAX_LINE], dirf [MAX_LINE],
- X full_arch_dir [MAX_LINE], full_farch_dir [MAX_LINE], error [MAX_LINE],
- X desc [MAX_LINE], _file [MAX_LINE];
- X char *p;
- X struct stat stat_buf;
- X BOOLEAN continued = FALSE, found;
- X
- X /* If file_part contains a directory, extract that into dir to append
- X to farch_dir and to arch_dir. */
- X strcpy (dir, file_part);
- X if (p = strrchr(dir, '/'))
- X strcpy (file, p + 1),
- X *p = EOS,
- X sprintf (full_arch_dir, "%s/%s", arch_dir, dir),
- X sprintf (full_farch_dir, "%s/%s", farch_dir, dir);
- X else
- X RESET (dir),
- X strcpy(file, file_part),
- X strcpy (full_arch_dir, arch_dir),
- X strcpy (full_farch_dir, farch_dir);
- X sprintf (dirf, "%s/%s/%s", ARCHIVE_DIR, full_farch_dir, DIRF);
- X if (!make_indexes (dirf, full_farch_dir, password, error, mask)) {
- X reject_archive (error, subject);
- X return;
- X }
- X
- X sprintf (error, "%s.old", dirf);
- X mv (dirf, error);
- X OPEN_FILE (fin, error, "r", "farch");
- X OPEN_FILE (fout, dirf, "w", "farch");
- X stat (fullpath, &stat_buf);
- X found = FALSE;
- X while (!feof (fin)) { /* Get location and file-count of file */
- X RESET (_file);
- X fscanf (fin, "%s", _file);
- X if (_file[0] != EOS) {
- X locase (_file);
- X if (!strcmp (_file, file)) {
- X fprintf (fout, "%s 1 %ld", file, stat_buf.st_size);
- X fscanf (fin, "%d %d", &dummy, &dummy);
- X found = TRUE;
- X do { /* Get file description */
- X RESET (desc);
- X fgets (desc, MAX_LINE - 2, fin);
- X fputs (desc, fout);
- X if (desc[0] != EOS && desc[strlen (desc) - 1] == '\n')
- X desc[strlen (desc) - 1] = EOS;
- X continued = FALSE;
- X if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
- X continued = TRUE;
- X } while (continued);
- X }
- X else {
- X fprintf (fout, "%s", _file);
- X do { /* Get file description */
- X RESET (desc);
- X fgets (desc, MAX_LINE - 2, fin);
- X fputs (desc, fout);
- X if (desc[0] != EOS && desc[strlen (desc) - 1] == '\n')
- X desc[strlen (desc) - 1] = EOS;
- X continued = FALSE;
- X if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
- X continued = TRUE;
- X } while (continued);
- X }
- X }
- X }
- X if (!found)
- X fprintf (fout, "%s 1 %ld %s %s\n", file, stat_buf.st_size, full_arch_dir,
- X subject);
- X fclose (fin);
- X fclose (fout);
- X unlink (error);
- X chmod (dirf, 0644 & (0644 ^ otoi (archives_mask)));
- X}
- X
- X/*
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- Xvoid reject_archive (char *msg, char *subject)
- X{
- X FILE *forwardmail = NULL;
- X char report_msg [MAX_LINE];
- X
- X sprintf (report_msg, "Cannot archive: %s", msg);
- X report_progress (report, report_msg, TRUE);
- X
- X create_header (&forwardmail, mailforwardf, sys.lists[listid].address,
- X sys.lists[listid].address, sys.lists[listid].owner,
- X subject, FALSE, TRUE, TRUE);
- X fprintf (forwardmail, "Cannot archive: %s\n", msg);
- X fprintf (forwardmail, "arch_dir: %s\n", sys.lists[listid].arch_dir);
- X fprintf (forwardmail, "arch_spec: %s\n", sys.lists[listid].arch_spec);
- X fprintf (forwardmail, "Here is the message that was not archived:\n\
- X------------------------------------------------------------------------------\
- X\n\n");
- X
- X if (copy_msg (forwardmail, msgf, FALSE, sys.lists[listid].address, 0, FALSE,
- X FALSE))
- X sendmail (sys.lists[listid].owner, FALSE, FALSE, 0, 0,
- X mailforwardf);
- X}
- X
- X/*
- X Look for a line like "volume <number> number <number>" and store
- X numbers in volume_num and issue_num.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- XBOOLEAN get_volume (char *message_file, int *volume_num, int *issue_num)
- X{
- X FILE *fp;
- X char line [MAX_LINE], *p;
- X BOOLEAN found = FALSE;
- X
- X OPEN_FILE (fp, message_file, "r", "get_volume");
- X while (!feof (fp) && !found) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, fp);
- X if (line [0] != EOS && line [strlen (line) - 1] == '\n')
- X line [strlen (line) - 1] = EOS;
- X
- X locase (line);
- X
- X for (p = line; *p != EOS && isspace (*p); p++);
- X if (strncmp (p, "volume", strlen ("volume")))
- X continue;
- X
- X for (p += strlen ("volume"); *p != EOS && isspace (*p); p++);
- X if (!isdigit (*p))
- X continue;
- X
- X *volume_num = atoi (p);
- X for (; *p != EOS && isdigit (*p); p++);
- X
- X for (; *p != EOS && isspace (*p); p++);
- X if (strncmp (p, "number", strlen ("number")))
- X continue;
- X
- X for (p += strlen ("number"); *p != EOS && isspace (*p); p++);
- X if (!isdigit (*p))
- X continue;
- X
- X *issue_num = atoi (p);
- X found = TRUE;
- X }
- X
- X fclose (fp);
- X return found;
- X}
- X
- X/*
- X Get the Archive-Name: if any.
- X*/
- X
- XBOOLEAN get_archive_name (char *message_file, char *archive_name)
- X{
- X FILE *fp;
- X char error [MAX_LINE], line[MAX_LINE];
- X
- X OPEN_FILE (fp, message_file, "r", "get_archive_name");
- X while (!feof (fp)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, fp);
- X locase (line);
- X clean_request (line);
- X if (re_strcmp (ARCHIVE_NAME, line, NULL) > 0) {
- X sscanf (line, "%s %s", error, archive_name);
- X fclose (fp);
- X return TRUE;
- X }
- X }
- X fclose (fp);
- X return FALSE;
- X}
- X
- X/*
- X Check if the daily limit of messages posted has been exceeded and return
- X immediately; otherwise, distribute no more than the limit minus messages
- X already posted and update the limits file.
- X*/
- X
- XBOOLEAN limit_exceeded (char *limitsf, char *list_mail_f, char *mail_copyf)
- X{
- X FILE *fin, *fout;
- X long int nmessages, mon, day, year;
- X#ifdef ultrix
- X time_t time_is;
- X#else
- X long int time_is;
- X#endif
- X struct tm *t;
- X char line [MAX_LINE];
- X char *tmprest;
- X
- X nmessages = mon = day = year = 0;
- X if ((fin = fopen (limitsf, "r")))
- X fscanf (fin, "%d %d %d %d", &nmessages, &mon, &day, &year),
- X fclose (fin);
- X if (nmessages > sys.lists[listid].max_messages)
- X return TRUE;
- X OPEN_FILE (fin, list_mail_f, "r", "limit_exceeded");
- X OPEN_FILE (fout, mail_copyf, "w", "limit_exceeded");
- X while (!feof (fin) && nmessages < sys.lists[listid].max_messages) {
- X ++nmessages;
- X RESET (line);
- X fgets (line, MAX_LINE - 2, fin);
- X do {
- X fputs (line, fout);
- X RESET (line);
- X fgets (line, MAX_LINE - 2, fin);
- X } while (!feof (fin) &&
- X (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE))));
- X if (!strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))
- X fseek (fin, -strlen (line), SEEK_CUR); /* Move back to beginning */
- X }
- X fclose (fout);
- X OPEN_FILE (fout, (tmprest = mystrdup (tmpnam (NULL))), "w", "limit_exceeded");
- X RESET (line);
- X while (!feof (fin))
- X RESET (line),
- X fgets (line, MAX_LINE - 2, fin),
- X fputs (line, fout);
- X fclose (fin);
- X fclose (fout);
- X mv (tmprest, list_mail_f);
- X free ((char *) tmprest);
- X time (&time_is);
- X t = localtime (&time_is);
- X echo (tsprintf ("%d %d %d %d", nmessages, t->tm_mon + 1, t->tm_mday,
- X t->tm_year), limitsf);
- X return FALSE;
- X}
- *-*-END-of-src/list.c-*-*
- echo x - src/listproc.c
- sed 's/^X//' >src/listproc.c <<'*-*-END-of-src/listproc.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | MAILING LIST PROCESSOR |
- X | |
- X | Version 6.0 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X This is the system's server. People send requests to ListProcessor for
- X subscription, removal of subscription, general information request, etc.
- X In addition, list owners issue administrative requests.
- X
- X The recognized user-commands are as follows:
- X help [command]
- X set <list> [<option> <arg[s]>] option: mail, password, address, conceal
- X arg: ack, noack, postpone, digest
- X args: current-password new-password
- X args: current-password new-address
- X arg: yes, no
- X subscribe <list> <name>
- X unsubscribe <list> (alias signoff)
- X recipients <list> (alias review)
- X information <list>
- X statistics <list> {[subscriber email address(es)] | [-all]}
- X lists
- X which
- X index [archive | path-to-archive] [/password] [-all]
- X get <archive | path-to-archive> <filename> [/password] [parts]
- X search <archive | path-to-archive> [/password] [-all] <pattern>
- X fax <fax-number> <archive | path-to-archive> <filename> [/password] [parts]
- X run <list> [<password> cmd [args]]
- X release
- X
- X List administration commands:
- X system <list> <password> <user-address> #<user-request>
- X reports <list> <password>
- X edit <list> <password> <file>
- X put <list> <password> <keyword> [args]
- X approve <list> <password> <tag>
- X discard <list> <password> <tag>
- X
- X Manager oriented commands:
- X shutdown <password>
- X restart <password>
- X execute <password> #<prog> [args]
- X
- X Above, <user-request> is any of the recognized user requests.
- X
- X Commands are sent to ListProcessor one on each line of the message. The user
- X is notified of the first invalid request; all subsequent commands
- X are ignored -- imagine someone sending an entire book!! For each
- X successfully completed command, a confirmation is sent back to the sender.
- X Commands/requests may be abbreviated.
- X
- X USER ORIENTED REQUESTS:
- X -----------------------
- X
- X The user may request help in general, or on a specific command; he can
- X 'set list mail ack' in which case his/her messages to the list will be
- X echoed back to him/her, and 'set list mail noack' (the opposite);
- X A 'set list mail postpone' request will not send any messages to the
- X subscriber until he resets it to one of the other options (used to suppress
- X sending email temporarily). 'set list mail digest' will only send messages
- X periodically as digests. 'set list' with no arguments returns the current
- X values for all options. The user may reset his/her password with the
- X 'set list password current-password new-password' request, and use this
- X password to alter the address he/she is subscribed with: 'set list address
- X current-password new-address'; he may hide his identity by issuing a
- X 'set list conceal yes' request.
- X
- X To subscribe to the list, a user has to give his/her full name;
- X he/she may leave the list by issuing an 'unsubscribe' request;
- X a list of the current subscribers is obtained through a 'recipients' request;
- X a copy of the sender's message is also sent to peer lists in this case.
- X Moreover, general information is available by means of an 'information'
- X request, and finally 'statistics' compiles a count of messages sent by
- X each subscriber (unless specific subscriber address are given) as well as
- X a total count of messages on file; again, a copy of the message will be
- X forwarded to all peer lists. Private lists do not allow non-members to
- X execute 'recipients' and 'statistics' requests.
- X
- X A list of all mailing lists served by this server can be obtained by
- X a 'lists' request.
- X
- X A listing of all lists a person is subscribed in is available via a
- X 'which' request.
- X
- X Information on the current release of this server can be obtained by
- X a 'release' request.
- X
- X Subscribers of a list may also run a set of UNIX commands as defined by the
- X system's manager via the 'run' request. Each command may have a different
- X password and may take arguments. Users receive the output from stdout and/or
- X stderr.
- X
- X The system includes a means for users to obtain files. The files
- X can be placed anywhere in the system and are archived under
- X HOMEDIR/archives/*
- X Each of these archives has an index of subarchives and a directory
- X of files that can be obtained from that archive; there is a master
- X archive in archives/listproc: the file INDEX contains names and full paths
- X to all of the archives (including listproc); the file DIR is a directory
- X of files that are archived under listproc. A user
- X may obtain a list of all the archives and their files by sending an
- X 'index' request. That request followed by a specific archive will
- X send a list of files for that archive and all of its subsrchives.
- X The format of the INDEX file is as follows: one line per archive
- X with the following:
- X
- X archive-name full-path-to-its-directory [password]
- X
- X When listing subarchives in INDEX the following rule has to be followed:
- X the first entry is the archive itself; all first level subarchives follow
- X (let's say A, B and C), then all second level subarchives (starting with
- X A's subarchives, then listing B's and last C's), then all third level
- X subarchives, etc. No sibling archives may have the same name.
- X
- X An archive is made private by putting a password after its full
- X path specification. This password has to be present in all parent
- X archives and is required for obtaining an index of that archive,
- X as well as any files from that archive.
- X
- X A file can be obtained via a 'get' request, specifying the archive and
- X the file to get. It is possible that a file has been split in various
- X parts, in which case multiple emails with the various subparts will
- X be sent to the user. Note that only the master index is used in this
- X case for locating the archive. Individual parts of the split file may
- X be obtained by specifying them as arguments.
- X
- X An archive's files may be searched for a pattern via the 'search' request.
- X The pattern is an egrep(1)-style regular expression with the additional
- X `&` (AND) and '~' (OR) loginal operators.
- X
- X A file may be archived with the farch utility, or manually by
- X editing the DIR file of the target archive. The format is as follows:
- X one line per file containing the following information:
- X
- X filename number-of-subparts size-of-each-part dir-where-found [Comments]
- X
- X The restriction is that the actual disk file should be all in lower case.
- X Private archives require a password for obtaining files.
- X
- X A new archive may be created by creating a subdirectory under
- X HOMEDIR/archives (the new directory may not be all in lower-case letters),
- X updating the master INDEX (archives/listproc/INDEX) and all lower-level
- X indeces (if any), creating a new INDEX file in the new directory with one
- X entry (the new archive itself), and creating an empty DIR file in the
- X same new directory.
- X
- X The hierarchical structure is only logical and directory hierarchy does
- X not matter. All archives though have to be placed under HOMEDIR/archives.
- X
- X All commands may be abbreviated except 'shutdown' and 'restart'.
- X
- X LIST OWNER ORIENTED REQUESTS:
- X -----------------------------
- X
- X The system includes support for list owners. These are list administrators
- X with special privileges on the system. They may issue requests on users'
- X behalf overriding any restriction set on regular users (these include
- X disabled commands also). The following requests are available to
- X list owners:
- X
- X system <list> <password> <user-address> #<user-request>
- X
- X This request overrides all system restrictions and executes <user-request>
- X on behalf of <user-address>; the address has to appear as listsed in the
- X .subscribers file, where applicable. The most frequent use of the 'system'
- X request is to subscribe a user to a private list. ListProcessor will send
- X a message to the owner igiving him the exact address and request to
- X issue back. For example:
- X
- X system herc herc1 user1@foo.com #subscribe herc Foo Bar
- X
- X As another example, to remove a user from a list, the owner issues:
- X
- X system herc herc1 user1@foo.com #unsubscribe herc
- X
- X Keep in mind that if the owner makes a syntax error in <user-request>,
- X <user-address> will be notified as if they issued the incorrect
- X request.
- X
- X A list owner may obtain all reports pertinent to the list he is maintaining
- X by issuing the following request:
- X
- X reports <list> <password>
- X
- X This will send two mail messages: one with the current report and one with
- X the previously archived ones.
- X
- X An owner may also obtain other files pertinent to his list via the
- X following request:
- X
- X edit <list> <password> <file>
- X
- X This will send a message containing the specified file.
- X
- X A list owner may also add aliases to the .aliases file, add users to the
- X .ignored file, change the welcoming message in .welcome, change
- X the informative message in .info, change the .subscribers/.peers/.news etc
- X by way of the 'put' request:
- X
- X put <list> <password> <keyword> [args]
- X
- X The keyword defines the action to be taken; valid keywords are: alias,
- X ignore, welcome, info. To add an alias, the following request may be
- X issued:
- X
- X put <list> <password> alias <new-alias> <address-as-subscribed>
- X
- X Refer to the man pages for explanation on aliases. To add to the .ignored
- X file:
- X
- X put <list> <password> ignore <address-as-subscribed-or-aliased>
- X
- X To create new .welcome/.info/.aliases/.ignored/.subscribers/.news/.peers
- X files the following requests may be issued:
- X
- X put <list> <password> welcome
- X put <list> <password> info
- X put <list> <password> aliases
- X put <list> <password> ignored
- X put <list> <password> subscribers
- X put <list> <password> news
- X put <list> <password> peers
- X
- X After the request, all text that follows is assumed to be the message
- X to be copied until the end of this message. Thus no more requests can
- X be made in the same mail message (they are treated as regular text).
- X
- X As a final note, list owners are authenticated by checking their
- X addresses in HOMEDIR/owners (a file containing all owners' addresses),
- X and verifying their passwords. There is no provision for adding restricted
- X users, adding new peers and connecting with news groups. These cases
- X have to be handled by the system's manager.
- X
- X A list owner may also approve messages for posting to his moderated
- X list via an 'approve' request. ListProcessor forwards every new message
- X to the owner providing him with the message's tag number. The
- X owner then replies with:
- X
- X approve <list> <password> <tag>
- X
- X ListProcessor then finds the message with the provided tag and prepares
- X it for posting. To discard a message, the owner sends the following
- X request:
- X
- X discard <list> <password> <tag>
- X
- X MANAGER ORIENTED REQUESTS:
- X --------------------------
- X
- X The entire system may be remotely shut down by way of a 'shutdown' request;
- X this request must be followed by a password that must match the one defined
- X in config. Note that this may result in requests being queued with the
- X 'shutdown' one not being serviced; note thought that a copy of the original
- X requests can be found in MAIL_COPY as defined in listproc.h.
- X Likewise, the system may be remotely restarted by issuing a 'restart'
- X request with the proper password. Note that a 'restart' request has no
- X effect after a 'shutdown' (because the server is not running), and that
- X any requests queued with the 'restart' will be serviced (the system will
- X not restart until all requests are serviced).
- X
- X ListProcessor lets the manager execute a command remotely via the 'execute'
- X request, and sends him the output from stdout and stderr in two separate
- X messages.
- X
- X COMMAND LINE OPTIONS:
- X -1: Same as for the list program.
- X -r: This option may be repeated an infinite number of times and is
- X always followed by a valid ListProcessor command (as outlined above).
- X This forces a restriction to be placed on the specified command;
- X whenever a user makes such a request, the request will be rejected
- X if the number of users currently on the system is greater than
- X the threshold specified in listproc.h. This option was added due
- X to the fact that the 'statistics' request may take up a lot of
- X resources to complete.
- X -e: Echo reports to the screen.
- X -n: Do not notify peer servers.
- X -d: Disable a ListProcessor command. This makes totally unknown to the server.
- X However, help is still available for the particular request.
- X -a: Usually, subscriptions are automatic. This option turns automatic
- X subscription off for the specified list. Such requests will be
- X forwarded to manager for approval.
- X -b: The command that follows will be executed in batch mode.
- X -B: Process the batch queue.
- X -i: Go to interactive mode. No mail is sent out and the text saved
- X in MAILFORWARD will be read by serverd.
- X -D: Turn debug on. A transaction of the last email sent out is kept
- X in the files HOMEDIR/sent and HOMEDIR/received. This assumes
- X use of the 'system' mail method.
- X
- X EXIT CODES:
- X 0: OK
- X 1: Could not open or lock file
- X 2: SIGINT signal
- X 3: Command line option error
- X 4: Syntax error in file
- X 5: Could not spawn
- X 6: Shutdown request
- X 7: Restart request
- X 8: Received system signal
- X 9: Too many multiple recipients
- X 10: Could not deliver mail
- X 11: Malloc failed
- X 12: Cannot fork
- X 13: Socket connection problem
- X 14: Semaphore error
- X 15: Cannot setuid, setgid
- X 16: Internal error
- X
- X Approximate algorithm:
- X {
- X Place a lock so that no other programs will access the same files.
- X Lock SERVER_MAIL_FILE or BATCH_FILE so catmail can't append to it
- X Read the SERVER_MAIL_FILE or BATCH_FILE
- X Unlock the file
- X
- X if new messages have arrived then {
- X For each message do {
- X If the message is sent by MAILER-DAEMON forward it to MANAGER
- X else {
- X if the person in not in the IGNORED file, then
- X scan each line of the body of the message and treat it as a
- X command with possible arguments. Reply to the sender for each such
- X request. If a request cannot be processed, send an error message to
- X the sender and ignore all subsequent requests.
- X }
- X }
- X }
- X }
- X
- X Required files:
- X SUBSCRIBERS <-- The list of subscribed people (diff. for each list)
- X ALIASES <-- Aliases of email addresses of subscribers, news &
- X peers.
- X PEERS <-- A list of peers for a particular list (where appl.)
- X IGNORED <-- The list of undesired people (one for the server
- X and one for each list)
- X
- X Input files:
- X HEADERS <-- Used for the 'statistics' request (see list.c)
- X SERVER_MAIL_FILE <-- Where new messages go
- X BATCH_FILE <-- Where requests are batched
- X MAIL_COPY <-- Copy of this file (actual work file)
- X MSG_NO <-- Read last message count
- X SUBSCRIBERS
- X IGNORED
- X
- X Output files:
- X SERVER_MBOX <-- A log of all messages sent
- X SUBSCRIBERS <-- After updating
- X OLD_SUBSCRIBERS <-- Temporary
- X MSG_NO <-- Write last message count
- X REPORT_SERVER <-- Progress report
- X MAILFORWARD <-- Completed message (with header and the
- X the body of the message) to be forwarded
- X
- X Format of the SUBSCRIBERS, PEERS and IGNORED files:
- X See comments for list.c
- X
- X*/
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#ifdef SYSLOG
- X# ifdef ultrix
- X# include <sys/syslog.h>
- X# else
- X# include <syslog.h>
- X# endif
- X#endif
- X#include <ctype.h>
- X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
- X && !defined (sequent) && !defined (unknown_port)
- X# include <malloc.h>
- X#endif
- X#include <string.h>
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <sys/stat.h>
- X#include <fcntl.h>
- X#include <signal.h>
- X#include <math.h>
- X#if !defined (stellar) && !defined (unknown_port)
- X# include <time.h>
- X#endif
- X#include <sys/time.h>
- X#if !defined (sequent) && !defined (__NeXT__) && !defined (__convex__) && \
- X !defined (apollo) && !defined (i386) && !defined (unknown_port)
- X# include <sys/termio.h>
- X#endif
- X#ifndef sun
- X# include <sys/ioctl.h>
- X#endif
- X#include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X#include "defs.h"
- X#include "listproc.h"
- X#include "struct.h"
- X#include "global.h"
- X#include "ilpp.h"
- X#if defined (__NeXT__) || defined (unknown_port)
- X# include "next.h"
- X#endif
- X
- X#ifdef TCP_IP
- X# include <sys/socket.h>
- X# include <netdb.h>
- X# include <netinet/in.h>
- Xstruct in_addr localaddr;
- X#else
- Xchar *localaddr;
- X#endif
- X
- X#ifdef GO_INTERACTIVE
- X# include <sys/ipc.h>
- X# include <sys/sem.h>
- X#endif
- X
- X/*
- X Function prototypes:
- X*/
- X
- X#ifdef __STDC__
- X# include "ansi/misc.h"
- X# include <stdarg.h>
- Xextern int syscom (char *, ...);
- Xextern int silp (char *, int, char *, char *, int, char *, char *, ...);
- Xextern char *tsprintf (char *, ...);
- X#else
- X# include "nonansi/misc.h"
- X# include <varargs.h>
- Xextern int syscom ();
- Xextern int silp ();
- Xextern char *tsprintf ();
- X#endif
- Xextern int sys_config (FILE *, SYS *);
- Xextern void report_progress (FILE *, char *, int);
- Xextern void init_signals (void);
- Xextern void catch_signals (void);
- Xextern void setup_string (char *, char *, char *);
- Xextern char *upcase (char *);
- Xextern char *locase (char *);
- Xextern void distribute (FILE *, void (*)(char *, char *, BOOLEAN),
- X FILE *, char *, char *, char *, char *, BOOLEAN);
- Xextern char *clean_name (char *);
- Xextern void clean_request (char *);
- Xextern int _getopt (int, char **, char *);
- Xextern void get_list_name (char *, char *);
- Xextern int get_list_id (char *, SYS *, int);
- Xextern void shrink (char *);
- Xextern void free_remote (REMOTE **);
- Xextern void check_aliases (char *, char *);
- Xextern void shadow_password (char *);
- Xextern void read_params (char *, char *, char *, FILE *, FILE *);
- Xextern BOOLEAN extract_subscriber (FILE *, char *, BOOLEAN);
- Xextern BOOLEAN extract_sender (char *);
- Xextern BOOLEAN sysmail (char *);
- Xextern BOOLEAN subscribed (FILE *, char *, char *, char *, char *, char *,
- X BOOLEAN);
- Xextern BOOLEAN strinstr (char *, char *);
- Xextern BOOLEAN ignore_sender (FILE *, char *, FILE *, BOOLEAN);
- Xextern BOOLEAN requested_part (char *, int);
- Xextern BOOLEAN owner_listed (char *, char *, char *, FILE *);
- Xextern BOOLEAN remove_msg (char *, int, FILE *);
- Xextern int lock_file (char *, int, int, BOOLEAN);
- Xextern void unlock_file (int);
- Xextern void escape_address (char *);
- Xextern int otoi (char *);
- Xextern int insert_word (char *, char **, int, int, int);
- Xextern char *_strstr (char *, char *);
- Xextern int re_strcmp (char *, char *, char *);
- Xextern char *mystrdup (char *);
- Xextern int echo (char *, char *);
- Xextern int echo_append (char *, char *);
- Xextern int mv (char *, char *);
- Xextern int cp (char *, char *);
- Xextern int cat_append (char *, char *);
- Xextern int touch (char *);
- Xextern int ucb_strftime (char *, int, char *, struct tm *);
- Xextern long int write_to_fd (int, char *, long int);
- Xextern int P (int, int);
- Xextern int V (int, int);
- Xextern void escape_re (char *);
- X
- Xvoid main (int, char **, char **);
- Xvoid process_message (char *, char *, BOOLEAN);
- Xvoid action (char *, char *, char *, BOOLEAN);
- Xvoid reply_code (int);
- Xvoid create_header (FILE **, char *, char *, char *, char *, BOOLEAN, int,
- X BOOLEAN, BOOLEAN);
- Xvoid reject_mail (char *, char *, char *, int, int);
- Xvoid System (char *, char *, char *);
- Xvoid get_sys_files (char *, char *, char *);
- Xvoid put (char *, char *, char *);
- Xvoid help (char *, char *, char *);
- Xvoid unsubscribe (char *, char *, char *);
- Xvoid subscribe (char *, char *, char *, BOOLEAN);
- Xvoid which (char *, char *, char *);
- Xvoid set (char *, char *, char *);
- Xvoid recipients (char *, char *, char *);
- Xvoid info (char *, char *, char *);
- Xvoid stats (char *, char *, char *);
- Xvoid Shutdown (char *, char *, char *);
- Xvoid restart (char *, char *, char *);
- Xvoid lists (char *, char *, char *);
- Xvoid Index (char *, char *, char *);
- Xvoid get (char *, char *, char *);
- Xvoid search (char *, char *, char *);
- Xvoid release (char *, char *, char *);
- Xvoid notify (char *, char *, char *);
- Xvoid approve (char *, char *, char *);
- Xvoid discard (char *, char *, char *);
- Xvoid notify_peer_servers (char *, char *, char *, char *);
- Xvoid execute (char *, char *, char *);
- Xvoid unix_cmd (char *, char *, char *);
- Xvoid init_commands (void);
- Xvoid usage (void);
- Xvoid server_config (char *);
- Xint gexit (int);
- X
- X/*
- X The control structure of the server. Check if mail has arrived.
- X If so, copy it to MAIL_COPY and proceed to lower level.
- X First, the command line options are analyzed (for restrictions, etc.).
- X*/
- X
- Xvoid main (int argc, char **argv, char **envp)
- X{
- X struct stat stat_buf;
- X char *options = "1r:d:enDa:b:c:BiS:F:R:C:", *mask;
- X int c;
- X BOOLEAN execute_once = FALSE, notok;
- X int i, j, k, rlfd = 2;
- X FILE *f;
- X extern char *optarg, *getenv();
- X extern int optopt;
- X#ifdef TCP_IP
- X struct hostent *lhost;
- X#endif
- X
- X prog = argv[0];
- X init_commands();
- X#ifdef SYSLOG
- X openlog ("ListProcessor: listproc", LOG_NDELAY
- X# ifndef i386
- X |LOG_NOWAIT
- X# endif
- X , SYSLOG);
- X# ifndef ultrix
- X setlogmask (LOG_UPTO (LOG_INFO));
- X# endif
- X#else
- X if ((report = fopen (REPORT_SERVER, "a")) == NULL)
- X fprintf (stderr, "listproc: Unable to open %s\n", REPORT_SERVER),
- X exit (1);
- X chmod (REPORT_SERVER, 384); /* 600 */
- X#endif
- X nlists = sys_config (report, &sys);
- X mailforwardf = MAILFORWARD;
- X replyf = ULISTPROCESSOR_REPLY;
- X RESET (requests_file);
- X while ((c = _getopt (argc, argv, options)) != EOF)
- X switch ((char) c) {
- X case '1': execute_once = TRUE; break;
- X case 'e': tty_echo = TRUE; break;
- X case 'i': interactive = TRUE;
- X case 'n': do_not_notify_peer_server = TRUE; break;
- X case 'S': sid = atoi (optarg); break;
- X case 'F': mailforwardf = mystrdup (optarg); break;
- X case 'R': strcpy (requests_file, optarg); break;
- X case 'C': replyf = mystrdup (optarg); break;
- X case 'a':
- X case 'c':
- X if ((listid = get_list_id (upcase (optarg), &sys, nlists)) < 0)
- X fprintf (stderr, "\nlistproc: Unknown list %s for -%c option\n",
- X optarg, c),
- X exit (3);
- X if (c == 'a')
- X sys.lists[listid].options |= NON_AUTO_SUB;
- X else if (c == 'c')
- X sys.lists[listid].options |= CONCEAL_LIST;
- X break;
- X case 'B': process_batch = TRUE; break;
- X case 'D': debug = TRUE; break;
- X case 'b':
- X case 'r':
- X case 'd':
- X notok = TRUE;
- X k = 0;
- X upcase (optarg);
- X for (i = 0; i < MAX_COMMANDS; ++i) {
- X notok &= (((j = strncmp (optarg, commands[i].name, strlen (optarg)))
- X != 0) ? 1 : 0);
- X if (!j) {
- X ++k;
- X if (c == 'r')
- X restricted_commands |= commands[i].mask;
- X else if (c == 'd')
- X disabled_commands |= commands[i].mask;
- X else if (c == 'b')
- X batched_commands |= commands[i].mask;
- X }
- X }
- X if (notok)
- X fprintf (stderr, "listproc: Unrecognized request '%s'\n", optarg),
- X exit (3);
- X if (k > 1) /* ambiguous command */
- X fprintf (stderr, "listproc: Ambiguous request '%s'\n", optarg),
- X exit (3);
- X break;
- X case ':':
- X fprintf (stderr, "listproc: Option '%c' requires an argument.\n",
- X optopt);
- X exit (3);
- X case '?':
- X default:
- X usage ();
- X }
- X if ((mask = getenv ("ULISTPROC_UMASK")))
- X umask (otoi (mask));
- X else
- X mask = "066",
- X umask (S_IRWXG|S_IRWXO); /* 600 */
- X if (!execute_once)
- X printf ("%s", COPYRIGHT);
- X init_signals();
- X catch_signals();
- X if (sys.options & USE_ENV_VAR) {
- X if ((sys.mail.method = (char *) malloc (256 * sizeof (char))) == NULL)
- X report_progress (report, "\nmain(): malloc() failed", TRUE),
- X gexit (11);
- X sprintf (sys.mail.method, "env - %s=%s %s ", sys.mail.env_var,
- X sys.server.address, sys.mail.mail_prog);
- X }
- X
- X if (!tty_echo) {
- X j = -1;
- X#if defined (TIOCNOTTY) && defined (SIGTTOU) && defined (SIGTTIN)
- X if ((i = open ("/dev/tty", 2)) >= 0)
- X j = ioctl (i, TIOCNOTTY, 0),
- X close (i);
- X#endif
- X if (j < 0 &&
- X#ifdef svr4
- X setsid ()
- X#else
- X# ifdef SETPGRP_NEEDS_ARGS
- X setpgrp (0, 0)
- X# else
- X setpgrp ()
- X# endif
- X#endif
- X < 0)
- X report_progress (report, "WARNING: could not detach from tty", TRUE);
- X }
- X
- X if ((f = fopen (tsprintf ("%s.%d", PID_SERVER, getpid()), "w")) != NULL)
- X fprintf (f, "%d", getpid()),
- X fclose (f);
- X signal (SIGINT, (void (*) ()) gexit);
- X signal (SIGALRM, SIG_IGN);
- X#ifdef TCP_IP
- X if (gethostname (hostname, sizeof (hostname)))
- X report_progress (report, tsprintf ("\nmain(): gethostname() failed: errno \
- X%d", errno), TRUE),
- X gexit (16);
- X if (!(lhost = gethostbyname (hostname)))
- X report_progress (report, tsprintf ("\nmain(): gethostbyname() failed: errno %d", errno), TRUE),
- X gexit (16);
- X memcpy ((char *) &localaddr, (char *) lhost->h_addr, lhost->h_length);
- X#else
- X localaddr = LOCAL_ADDR;
- X strcpy (hostname, HOSTNAME);
- X#endif
- X
- X if (process_batch) /* Select file to process: batch or requests */
- X strcpy (requests_file, BATCH_FILE);
- X else if (!interactive)
- X strcpy (requests_file, SERVER_MAIL_FILE);
- X
- X#ifdef GO_INTERACTIVE
- X if (requests_file[0] == EOS)
- X fprintf (stderr, "\nmain(): -R option required\n"),
- X gexit (3);
- X#endif
- X
- X do {
- X if (!stat (requests_file, &stat_buf) && stat_buf.st_size > 0) {
- X#ifndef NO_LOCKS
- X if ((rlfd = lock_file (requests_file, O_RDWR, 0, FALSE)) < 0)
- X report_progress (report, tsprintf ("\nmain(): Cannot open or lock %s",
- X requests_file), TRUE),
- X gexit (1); /* Cannot lock file, so exit, regardless of execute_once */
- X#endif
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("main", SEM_SYSFILES);
- X#endif
- X if (!interactive)
- X cp (requests_file, MAIL_COPY);
- X if (!process_batch)
- X cat_append (requests_file, SERVER_MBOX),
- X echo_append ("", SERVER_MBOX);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("main", SEM_SYSFILES);
- X#endif
- X if (!interactive && !unlink (requests_file))
- X touch (requests_file), /* rewrite file */
- X chmod (requests_file, /*384*/ 0666 & (0666 ^ otoi (mask)));
- X#ifndef NO_LOCKS
- X unlock_file (rlfd);
- X#endif
- X OPEN_FILE (mail, (!interactive ? MAIL_COPY : requests_file), "r", "main");
- X if (process_batch)
- X report_progress (report, PROCESSING_BATCH, FALSE);
- X else
- X report_progress (report, NEW_ARRIVAL, FALSE);
- X distribute (mail, (void (*)(char *, char *, BOOLEAN)) process_message,
- X report, NULL, NULL, NULL, NULL, TRUE);
- X fclose (mail); /* Done */
- X shrink (message_idsf);
- X if (!interactive)
- X unlink (MAIL_COPY); /* Done delivering */
- X }
- X else if (!execute_once) /* No mail to deliver */
- X if (sys.frequency > 0)
- X sleep (sys.frequency);
- X } while (!execute_once);
- X#ifdef SYSLOG
- X closelog ();
- X#else
- X fclose (report);
- X#endif
- X free_remote (&rlists);
- X if (restart_sys)
- X gexit (7); /* Exit status of 7 signifies a restart request */
- X gexit (0);
- X}
- X
- X/*
- X Process each message. Isolate each command and pass it to action().
- X Before that, check if the message is from MAILER_DAEMON, in which case
- X forward the message to MANAGER. Any messages from people listed in the
- X IGNORED file are not processed.
- X Note: Please look at the documentation for list.c for the definition of a
- X mailer daemon.
- X*/
- X
- Xvoid process_message (char *sender, char *linecopy, BOOLEAN address_ok)
- X{
- X char line [MAX_LINE]; /* ... from the current message */
- X char _line [MAX_LINE];
- X char request [MAX_LINE]; /* holds each command */
- X char sender_copy [MAX_LINE];
- X char senders_subject [MAX_LINE];
- X char id_copy [MAX_LINE];
- X char original_sender [MAX_LINE];
- X char received [MAX_LINE];
- X char precedence [MAX_LINE]; /* Holds the Precedence: */
- X char match [MAX_LINE];
- X char error [MAX_LINE];
- X char *at = NULL;
- X FILE *f;
- X BOOLEAN loop = FALSE;
- X BOOLEAN did_action;
- X BOOLEAN done;
- X BOOLEAN fake_mail = TRUE;
- X BOOLEAN mailer_daemon;
- X BOOLEAN susp_subject;
- X long int offset;
- X
- X listid = -1;
- X peer_server_request = FALSE;
- X line[0] = message_id[0] = id_copy[0] = precedence[0] = received[0] =
- X original_sender[0] = senders_subject[0] = RESET (sender_copy);
- X strcpy (sender_copy, sender); /* We do not like converting the actual */
- X upcase (sender_copy); /* address to upper case */
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("process_message", SEM_REQ_ID);
- X#endif
- X if ((msg_no = fopen (MSG_NO, "r")) != NULL)
- X fscanf (msg_no, "%d\n", &request_no),
- X fclose (msg_no);
- X report_progress (report, tsprintf ("Request #%04d:%s\n", ++request_no,
- X (*sender != EOS ? sender : "\"\"")), FALSE);
- X OPEN_FILE (msg_no, MSG_NO, "w", "process_message");
- X fprintf (msg_no, "%d\n", request_no);
- X fclose (msg_no);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("process_message", SEM_REQ_ID);
- X#endif
- X
- X while (!feof (mail) && line[0] != '\n') { /* Skip to beginning of message */
- X strcpy (match, "\\1");
- X if (re_strcmp (SUBJECT, line, match) > 0) {
- X strcpy (senders_subject, line + strlen (match));
- X sprintf (line, "%s", line + strlen (match));
- X strcpy (match, "\\1");
- X if (re_strcmp (PEER_SERVER_REQUEST, line, match) > 0)
- X peer_server_request = TRUE;
- X }
- X else if (re_strcmp (FROM, line, match) > 0)
- X strcpy (original_sender, line + strlen (match)), /* Save From: */
- X original_sender [strlen (original_sender) - 1] = EOS; /* \n -> \0 */
- X else if (re_strcmp (RECEIVED, line, match) > 0) { /* Check for fake mail */
- X strcpy (received, line + strlen (match));
- X received [strlen (received) - 1] = EOS;
- X sscanf (received, "%s %s", error, received); /* Get host after "from" */
- X upcase (received); /* Relay host */
- X if (fake_mail && (at = strchr (sender_copy, '@')))
- X if (re_strcmp (at + 1, received, NULL) > 0)
- X fake_mail = FALSE;
- X }
- X else if (re_strcmp (PRECEDENCE, line, match) > 0)
- X strcpy (precedence, line + strlen (match)), /* Remove "Precedence: " */
- X precedence [strlen (precedence) - 1] = EOS,
- X upcase (precedence);
- X else if (re_strcmp (MESSAGE_ID1, line, NULL) > 0 ||
- X re_strcmp (MESSAGE_ID2, line, NULL) > 0 ||
- X re_strcmp (MESSAGE_ID3, line, NULL) > 0)
- X strcpy (message_id, line + strlen ("Message-") + 4),
- X message_id [strlen (message_id) - 1] = EOS, /* \n -> \0 */
- X strcpy (id_copy, message_id);
- X upcase (id_copy);
- X RESET (line);
- X fgets (line, MAX_LINE - 2, mail);
- X }
- X
- X offset = ftell (mail);
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("process_message", SEM_SYSFILES);
- X#endif
- X if (re_strcmp (LOW_PRECEDENCES, precedence, NULL) > 0) {
- X NOTIFY_MANAGER_OF_MSG_IGNORED ("Low Precedence: %s message ignored.",
- X precedence, "process_message");
- X loop = TRUE;
- X }
- X SETUP_MESSAGE_IDSF;
- X if (message_id[0] != EOS) { /* Check for mail loop using Message-Id: */
- X if (message_ids = fopen (message_idsf, "r")) {
- X if (ignore_sender (message_ids, id_copy, report, TRUE)) {
- X NOTIFY_MANAGER_OF_MSG_IGNORED ("The Message-Id: %s matches entries\n\
- Xin the .message.ids file.", id_copy, "process_message");
- X loop = TRUE;
- X }
- X fclose (message_ids);
- X }
- X if (!loop) {
- X OPEN_FILE (message_ids, message_idsf, "a", "process_message");
- X fprintf (message_ids, "%s %s\n", message_id, sender); /* Save new id */
- X fclose (message_ids);
- X }
- X }
- X /* Check for mail loop using Message-Id: and X-Listprocessor-Version: in
- X the body */
- X while (!feof (mail) &&
- X (strncmp (_line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {
- X RESET (_line);
- X fgets (_line, MAX_LINE - 2, mail);
- X if (re_strcmp (MESSAGE_ID1, _line, NULL) > 0 ||
- X re_strcmp (MESSAGE_ID2, _line, NULL) > 0 ||
- X re_strcmp (MESSAGE_ID3, _line, NULL) > 0) {
- X strcpy (id_copy, _line + strlen ("Message-") + 4);
- X id_copy [strlen (id_copy) - 1] = EOS; /* \n -> \0 */
- X upcase (id_copy);
- X if (message_ids = fopen (message_idsf, "r")) {
- X if (ignore_sender (message_ids, id_copy, report, TRUE)) {
- X NOTIFY_MANAGER_OF_MSG_IGNORED ("The Message-Id: %s matches entries\n\
- Xin the .message.ids file.", id_copy, "process_message");
- X loop = TRUE;
- X }
- X fclose (message_ids);
- X }
- X }
- X else if (re_strcmp (LISTPROC_ID, _line, NULL) > 0)
- X report_progress (report, "Found X-Listprocessor-Version: id in message \
- Xbody; message ignored", TRUE),
- X loop = TRUE;
- X }
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("process_message", SEM_SYSFILES);
- X#endif
- X fseek (mail, offset, SEEK_SET);
- X
- X if (!address_ok) {
- X RESET (request);
- X NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS (sender);
- X one_rejection = TRUE;
- X }
- X
- X mailer_daemon = strinstr (MAILER_DAEMON, sender_copy) ||
- X (original_sender[0] != EOS && strinstr (MAILER_DAEMON, original_sender)) ||
- X *sender == EOS;
- X susp_subject = (senders_subject[0] != EOS &&
- X strinstr (SUSP_SUBJECT, senders_subject));
- X if (mailer_daemon || susp_subject) {
- X /* Send message to MANAGER */
- X create_header (&f, mailforwardf, sys.server.address, sys.manager,
- X senders_subject, FALSE, INVALID_REQ, TRUE, TRUE);
- X fprintf (f, "\nRejected message: sent to %s by %s follows.\n\
- XReason for rejection: %s.\n--------------------------------------\
- X-----------------------------------------\n", sys.server.address,
- X (*sender != EOS ? sender : "\"\""),
- X (mailer_daemon ? "suspicious address" :
- X (susp_subject ? "suspicious subject" : "???")));
- X RESET (line);
- X while (!feof (mail) &&
- X (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {
- X fprintf (f, "%s", line);
- X RESET (line);
- X fgets (line, MAX_LINE - 2, mail);
- X }
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sys.manager, FALSE);
- X report_progress (report,
- X tsprintf ("Forwarding message to %s (%s)\n", sys.manager,
- X (mailer_daemon ? "suspicious address" :
- X (susp_subject ? "suspicious subject" : "???"))),
- X FALSE);
- X did_action = TRUE;
- X }
- X else { /* Isolate request and call action() */
- X check_aliases (ALIASESF, sender);
- X done = did_action = FALSE;
- X if (!interactive && fake_mail && at && !one_rejection && !loop)
- X report_progress (report,
- X tsprintf ("*** Possible fake mail: Host %s in user \
- Xaddress does\nnot match any of the domains in the Received: header lines.\n",
- X at + 1), FALSE);
- X while (!feof (mail) &&
- X (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {
- X clean_request (line);
- X RESET (request);
- X sscanf (line, "%s ", request);
- X upcase (request);
- X if (!strcmp (request, START_OF_SIGNATURE) || strinstr (THANKS, request))
- X done = TRUE; /* End of requests, start of .signature */
- X else if (request[0] != EOS && !one_rejection && !loop && !done)
- X if (!re_strcmp ("[Oo][Ff][Ff][Ii][Cc][Ee][ \t]+[Mm][Ee][Mm][Oo]|\
- XSubject|:[ \t]*.$|^\\>|^\\]|^\\||^#|^%|^\\}|^\\$", line, NULL))
- X action (line, request, sender, FALSE),
- X did_action = TRUE;
- X RESET (line);
- X fgets (line, MAX_LINE - 2, mail);
- X }
- X }
- X if (!did_action && !one_rejection && !loop) {
- X create_header (&f, mailforwardf, sys.server.address, sender,
- X "No requests found", FALSE, INVALID_REQ, FALSE, FALSE);
- X fprintf (f, "No requests found in your message. Requests should be \
- Xincluded in the\nbody of the mail message.\n");
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, FALSE);
- X }
- X strcpy (linecopy, line);
- X one_rejection = FALSE;
- X report_progress (report, "", -TRUE); /* -TRUE for no leading newline */
- X}
- X
- X/*
- X Recognize the 'request' and call the appropriate routine, or reject the
- X message if the request is not recognized. Isolate any parameters.
- X If a restriction is in force for the recognized request, then get
- X the number of users currently on the system and reject the request if
- X this number is greater that the predetermined threshold.
- X A request may be batched if we are not processing the batch queue and
- X the specified request is indeed to be batched according to the command
- X line options.
- X*/
- X
- Xvoid action (char *line, char *request, char *sender, BOOLEAN override)
- X{
- X char params [MAX_LINE];
- X char error [MAX_LINE];
- X char list_name [MAX_LINE];
- X char *users_file;
- X int i, nusers;
- X FILE *f, *ignored;
- X#ifdef ultrix
- X time_t time_is = 0;
- X#else
- X long int time_is = 0;
- X#endif
- X struct tm *t;
- X
- X report_progress (report, line, FALSE);
- X listid = -1;
- X RESET (error);
- X SETUP_IGNOREDF;
- X if ((ignored = fopen (server_ignoredf, "r"))) { /* No file for remote list */
- X if (ignore_sender (ignored, sender, report, FALSE)) {
- X NOTIFY_MANAGER_OF_MSG_IGNORED ("The sender's address (%s) matches \
- Xentries\nin the .ignored file.", sender, "action");
- X fclose (ignored);
- X goto abort;
- X }
- X fclose (ignored);
- X }
- X upcase (sender);
- X original_params[0] = RESET (params);
- X read_params (line, params, request, mail, report);
- X strcpy (original_params, params); /* Preserve case */
- X upcase (params);
- X for (i = 0; i < MAX_COMMANDS; i++) /* Walk through the valid requests */
- X if (! strncmp (request, commands[i].name, strlen (request)) &&
- X strlen (request) > 2 && ! (disabled_commands & commands[i].mask)) {
- X if (strncmp (request, "SHUTDOWN", strlen (request)) &&
- X strncmp (request, "RESTART", strlen (request)) &&
- X strncmp (request, "LISTS", strlen (request)) &&
- X strncmp (request, "INDEX", strlen (request)) &&
- X strncmp (request, "GET", strlen (request)) &&
- X strncmp (request, "FAX", strlen (request)) &&
- X strncmp (request, "VIEW", strlen (request)) &&
- X strncmp (request, "SEARCH", strlen (request)) &&
- X strncmp (request, "RELEASE", strlen (request)) &&
- X strncmp (request, "WHICH", strlen (request)) &&
- X strncmp (request, "NOTIFY", strlen (request)) &&
- X strncmp (request, "EXECUTE", strlen (request)) &&
- X strncmp (request, "HELP", strlen (request))) {
- X get_list_name (params, list_name);
- X listid = get_list_id (list_name, &sys, nlists);
- X server_config (list_name);
- X if (listid < 0) {
- X if (list_name[0] == EOS)
- X sprintf (error, "%s: Missing list name\n\n\
- XSyntax: %s <list> [...]\n", request, request);
- X else
- X sprintf (error, "%s: Unknown list name %s\n", request, list_name);
- X reject_mail (sender, line, error, SYNTAX_ERROR, REJECT_LIST);
- X return;
- X }
- X if ((ignored = fopen (ignoredf, "r"))) { /* No file for remote list */
- X if (ignore_sender (ignored, sender, report, FALSE)) {
- X NOTIFY_MANAGER_OF_MSG_IGNORED ("The sender's address (%s) matches \
- Xentries\nin the .ignored file.", sender, "action");
- X fclose (ignored);
- X goto abort;
- X }
- X fclose (ignored);
- X }
- X if (commands[i].mask & sys.lists[listid].disabled_commands &&
- X !override) {
- X reject_mail (sender, line,
- X tsprintf ("%s requests for list %s are disabled\n",
- X request, sys.lists[listid].alias),
- X INVALID_REQ, 0);
- X goto abort;
- X }
- X }
- X if (restricted_commands & commands[i].mask && !override) {
- X /* Restriction set */
- X syscom ("%s | %s \
- X'{ \
- X for (i = 1; i < 20; i++) \
- X if ($i == \"users,\") \
- X print $(i-1);\
- X}' > %s",
- X UPTIME, AWK, (users_file = mystrdup (tmpnam (NULL))));
- X OPEN_FILE (f, users_file, "r", "action");
- X fscanf (f, "%d", &nusers);
- X fclose (f);
- X unlink (users_file);
- X free ((char *) users_file);
- X if (nusers > sys.users) {
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X FALSE, RESTRICTED_REQ, FALSE, FALSE);
- X fprintf (f, "This request takes a considerable amount of resources \
- Xand certain restrictions\nare currently in force. Please resubmit your \
- Xrequest at a later time.\n");
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, FALSE);
- X strcat (request, ": restriction enforced\n");
- X report_progress (report, request, FALSE);
- X goto abort;
- X }
- X }
- X if (!process_batch &&
- X (batched_commands & commands[i].mask)) { /* Batch request */
- X time (&time_is);
- X t = localtime (&time_is);
- X if (t->tm_hour >= sys.batch.start &&
- X t->tm_hour <= (sys.batch.stop - 1)) { /* Between 8am and 8pm */
- X if (interactive) { /* Cannot batch a "live" request */
- X OPEN_FILE (f, mailforwardf, "w", "action");
- X fprintf (f, ">%s\nThe request cannot be processed at this time: \
- Xbatch mode in effect.\nPlease send email.\n", line);
- X fclose (f);
- X goto abort;
- X }
- X OPEN_FILE (f, BATCH_FILE, "a", "action");
- X time_is = time (0);
- X fprintf (f, "From %s %s\n\n%s\n", sender, ctime (&time_is), line);
- X fclose (f);
- X report_progress (report, "(request placed in the batch queue)\n",
- X FALSE);
- X goto abort;
- X }
- X }
- X commands[i].func (request, params, sender, override); /* Call routine */
- X goto abort;
- X }
- X if (! (sys.options & IGNR_INVLD_RQSTS) || interactive)
- X reject_mail (sender, line, tsprintf ("Unrecognized request %s\n", request),
- X INVALID_REQ, REJECT_REQUEST);
- X else
- X report_progress (report, "[ignored]\n", FALSE);
- X abort: ;
- X}
- X
- X/*
- X Produce the reply code during a live session.
- X*/
- X
- Xvoid reply_code (int reply)
- X{
- X FILE *f;
- X
- X OPEN_FILE (f, replyf, "w", "reply_code");
- X fprintf (f, "%d\n", reply);
- X fclose (f);
- X}
- X
- X/*
- X Create a message header addressed to 'sender' with the given 'subject'.
- X If this a reply to an invalid request, 'copy_owner' should be TRUE.
- X*/
- X
- Xvoid create_header (FILE **f, char *filename, char *sender, char *recipient,
- X char *subject, BOOLEAN copy_owner, int reply,
- X BOOLEAN preserve_msg_id, BOOLEAN error_condition)
- X{
- X#ifdef NEED_DATE
- X char date [80];
- X# ifdef ultrix
- X time_t time_is;
- X# else
- X long int time_is;
- X# endif
- X struct tm *t;
- X#endif
- X
- X if (interactive)
- X reply_code (reply);
- X OPEN_FILE (*f, filename, "w", "create_header");
- X locase (recipient);
- X if (subject [0] != EOS && subject [strlen (subject) - 1] == '\n')
- X subject [strlen (subject) - 1] = EOS;
- X if (interactive)
- X return;
- X if (!fax_it && sys.options & USE_TELNET) {
- X fprintf (*f, "HELO %s\nMAIL From: <%s>\nRCPT To: <%s>\n",
- X#ifdef ZMAILER
- X/*
- X# ifdef TCP_IP
- X (char *) inet_ntoa (localaddr),
- X# else
- X localaddr,
- X# endif
- X Use either the local address or the host name.
- X*/
- X hostname,
- X#else
- X "",
- X#endif
- X sender, recipient);
- X if (copy_owner)
- X fprintf (*f, "RCPT To: <%s>\n",
- X (listid >= 0 ? sys.lists[listid].owner : sys.manager));
- X fprintf (*f, "DATA\n");
- X }
- X if (preserve_msg_id && message_id[0] != EOS)
- X fprintf (*f, "Message-Id: %s\n", message_id);
- X#ifdef NEED_DATE
- X time (&time_is);
- X t = localtime (&time_is);
- X ucb_strftime (date, 1024, "%a, %e %b %Y %T %Z", t);
- X fprintf (*f, "Date: %s\n", date);
- X#endif
- X#ifndef NO_ERRORS_TO
- X fprintf (*f, "Errors-To: %s\n",((listid < 0 || listid == nlists) ?
- X sys.manager : sys.lists[listid].owner));
- X#endif
- X fprintf (*f, "Reply-To: %s\nSender: %s\nFrom: %s\nTo: %s\n",
- X sender, sender, sender, recipient);
- X if (copy_owner && !fax_it)
- X fprintf (*f, "Cc: %s\n",
- X ((listid >= 0 && listid < nlists) ?
- X sys.lists[listid].owner : sys.manager));
- X fprintf (*f, "Subject: %s%s\nX-Listprocessor-Version: %s\n",
- X (error_condition ? ERROR_CONDITION : ""), subject, VERSION);
- X if (sys.server.comment[0] != EOS)
- X fprintf (*f, "X-Comment: %s\n\n", sys.server.comment);
- X else
- X fprintf (*f, "\n");
- X}
- X
- X/*
- X Send a message to 'sender' indicating an invalid request. The body of
- X the message is given in 'text'. Only one such mail is sent to the user
- X for each of his/her invalid requests. All subsequent requests are ignored.
- X*/
- X
- Xvoid reject_mail (char *sender, char *request, char *text, int reply, int why)
- X{
- X FILE *f;
- X char *newline;
- X
- X if (one_rejection)
- X return;
- X one_rejection = TRUE;
- X create_header (&f, mailforwardf, sys.server.address, sender,
- X "Invalid request", COPY_OWNER (ccerrors), reply, FALSE, TRUE);
- X fprintf (f, ">%s\n%s\n", request, text);
- X if ((newline = strchr (text, '\n')))
- X *(newline + 1) = EOS;
- X report_progress (report, text, FALSE);
- X if (interactive) {
- X fclose (f);
- X return;
- X }
- X fprintf (f, "Report any problems to '%s'.\nFor a list of the \
- Xavailable requests send a message to %s\nwith a body consisting of nothing \
- Xbut the word HELP\n\nPS: Any subsequent requests that you might have \
- Xsubmitted have been ignored.\n",
- X ((listid < 0 || listid == nlists) ?
- X sys.manager : sys.lists[listid].owner),
- X sys.server.address);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, COPY_OWNER (ccerrors));
- X}
- X
- X/*
- X Execute a system request. This is usually a request issued by the
- X list's owner. System requests are valid only for the list the password
- X is given for.
- X*/
- X
- Xvoid System (char *request, char *params, char *sender)
- X{
- X char password [MAX_LINE];
- X char newrequest [MAX_LINE];
- X char newsender [MAX_LINE];
- X char list [MAX_LINE];
- X char *comment, *c;
- X int target_listid;
- X FILE *f;
- X
- X newsender[0] = newrequest[0] = list[0] = RESET (password);
- X sscanf (params, "%s ", password);
- X if ((c = _strstr (params, password))) {
- X while (*c != EOS && !isspace (*c)) /* Get to the end of password */
- X ++c;
- X while (*c != EOS && isspace (*c)) /* Get to new sender address */
- X ++c;
- X sprintf (newsender, "From %s", c);
- X if (!extract_sender (newsender)) { /* Error in address scanning */
- X shadow_password (params);
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params);
- X NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS (newsender);
- X return;
- X }
- X }
- X shadow_password (params);
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params);
- X if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
- X NOT_LIST_OWNER; /* Hacker attack */
- X return;
- X }
- X if (password[0] == EOS) {
- X reject_mail (sender, request, "Missing password for SYSTEM request\n\n\
- XSyntax: system <list> <password> <address> #<user-request>\n",
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (password[0] == '#' || strcmp (password, sys.lists[listid].password)) {
- X reject_mail (sender, request, "Invalid password for SYSTEM request\n",
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (newsender[0] == EOS || newsender[0] == '#') {
- X reject_mail (sender, request, "Missing user address for SYSTEM request\n\n\
- XSyntax: system <list> <password> <address> #<user-request>\n",
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (!(comment = strchr (params, '#'))) { /* No actual request */
- X reject_mail (sender, request, "Missing '#': no system request specified\n\n\
- XSyntax: system <list> <password> <address> #<user-request>\n",
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X sprintf (params, "%s", comment + 1); /* Remove password + sender address */
- X clean_request (params); /* Now we have the actual request */
- X sscanf (params, "%s %s", newrequest, list);
- X if (strlen (newrequest) < 3) {
- X reject_mail (sender, request, tsprintf ("Ambiguous request %s\n",
- X newrequest), SYNTAX_ERROR, 0);
- X return;
- X }
- X if (strncmp (newrequest, "SHUTDOWN", strlen (newrequest)) &&
- X strncmp (newrequest, "RESTART", strlen (newrequest)) &&
- X strncmp (newrequest, "LISTS", strlen (newrequest)) &&
- X strncmp (newrequest, "SEARCH", strlen (newrequest)) &&
- X strncmp (newrequest, "INDEX", strlen (newrequest)) &&
- X strncmp (newrequest, "GET", strlen (newrequest)) &&
- X strncmp (newrequest, "FAX", strlen (newrequest)) &&
- X strncmp (newrequest, "VIEW", strlen (newrequest)) &&
- X strncmp (newrequest, "RELEASE", strlen (newrequest)) &&
- X strncmp (newrequest, "WHICH", strlen (newrequest)) &&
- X strncmp (newrequest, "NOTIFY", strlen (newrequest)) &&
- X strncmp (newrequest, "EXECUTE", strlen (newrequest)) &&
- X strncmp (newrequest, "HELP", strlen (newrequest)) &&
- X list[0] != EOS) { /* Check target list validity */
- X if ((target_listid = get_list_id (list, &sys, nlists)) < 0) {
- X reject_mail (sender, request, tsprintf ("Unknown list %s\n", list),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (listid != target_listid) { /* Owner is cheating */
- X reject_mail (sender, request,
- X tsprintf ("Invalid request for list %s; SYSTEM requests \
- Xshould be made only\nfor list %s.\n",
- X list, sys.lists[listid].alias), INVALID_REQ, 0);
- X return;
- X }
- X }
- X action (params, newrequest, newsender, TRUE);
- X}
- X
- X/*
- X Provide the list owner with the requested files. The accumulated
- X report file is then shrunk. When a file is edited, the last modification
- X time is saved to prevent a subsequent put in case the file got modified
- X in the meantime.
- X*/
- X
- Xvoid get_sys_files (char *request, char *params, char *sender)
- X{
- X char password [MAX_LINE];
- X char req [MAX_LINE];
- X char file [MAX_LINE];
- X char extra [MAX_LINE];
- X FILE *f;
- X struct stat stat_buf;
- X
- X req[0] = extra[0] = file[0] = RESET (password);
- X strcpy (req, request);
- X sscanf (params, "%s %s %s", password, file, extra);
- X shadow_password (params);
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params);
- X if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
- X NOT_LIST_OWNER; /* Hacker attack */
- X return;
- X }
- X if (password[0] == EOS) {
- X reject_mail (sender, request,
- X tsprintf ("Missing password for %s request\n\n%s\n", req,
- X (!strncmp (req, "EDIT", strlen (req)) ?
- X "Syntax: edit <list> <password> <file>\n\
- X\tfile: subscribers/aliases/ignored/\
- Xnews/peers/info/welcome" : "Syntax: reports <list> <password>")),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (strcmp (password, sys.lists[listid].password)) {
- X reject_mail (sender, request,
- X tsprintf ("Invalid password for %s request\n", req),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (!strncmp (req, "REPORTS", strlen (req))) { /* Send reports */
- X if (file[0] != EOS) {
- X reject_mail (sender, request,
- X tsprintf ("Too many arguments to REPORTS ... : %s\n\n\
- XSyntax: reports <list> <password>\n", file), SYNTAX_ERROR, 0);
- X return;
- X }
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
- X OK, FALSE, FALSE);
- X#ifndef SYSLOG
- X fprintf (f, "*** Here is the latest report file:\n\n");
- X#else
- X fprintf (f, "Sorry, this system is using syslog(3) and no reports are \
- Xavailable.\n");
- X#endif
- X fclose (f);
- X#ifndef SYSLOG
- X setup_string (report_listf, sys.lists[listid].alias, REPORT_LIST);
- X cat_append (report_listf, mailforwardf);
- X#endif
- X APPEND_TELNET ("get_sys_files");
- X DELIVER_MAIL (sender, FALSE);
- X#ifndef SYSLOG
- X if (!interactive)
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X FALSE, OK, FALSE, FALSE);
- X else
- X OPEN_FILE (f, mailforwardf, "a", "get_sys_files");
- X fprintf (f, "*** Here is the accumulated report file; this file was shrunk \
- Xafter it was sent\nto you, so you may wish to save it:\n\n");
- X fclose (f);
- X setup_string (report_listf, sys.lists[listid].alias, REPORT_LIST_ACC);
- X cat_append (report_listf, mailforwardf);
- X APPEND_TELNET ("get_sys_files");
- X DELIVER_MAIL (sender, FALSE);
- X# ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("get_sys_files", SEM_SYSFILES);
- X# endif
- X shrink (report_listf);
- X# ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("get_sys_files", SEM_SYSFILES);
- X# endif
- X#endif
- X }
- X else { /* Request is EDIT */
- X if (extra[0] != EOS) {
- X reject_mail (sender, request,
- X tsprintf ("Too many arguments to EDIT ... %s: %s\n\n\
- XSyntax: edit <list> <password> <file>\n\
- X\tfile: subscribers/aliases/ignored/\
- Xnews/peers/info/welcome\n", file, extra), SYNTAX_ERROR, 0);
- X return;
- X }
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
- X OK, FALSE, FALSE);
- X# ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("get_sys_files", SEM_LISTFILES);
- X# endif
- X if (!strcmp (file, "ALIASES")) { /* Send .aliases */
- X fprintf (f, "*** Here is the aliases file:\n\n");
- X fclose (f);
- X cat_append (aliasesf, mailforwardf);
- X APPEND_TELNET ("get_sys_files");
- X DELIVER_MAIL (sender, FALSE);
- X PUT_TIMESTAMP (aliasesf, aliases_timestampf);
- X }
- X else if (!strcmp (file, "IGNORED")) { /* Send .ignored */
- X fprintf (f, "*** Here is the ignored file:\n\n");
- X fclose (f);
- X cat_append (ignoredf, mailforwardf);
- X APPEND_TELNET ("get_sys_files");
- X DELIVER_MAIL (sender, FALSE);
- X PUT_TIMESTAMP (ignoredf, ignored_timestampf);
- X }
- X else if (!strcmp (file, "INFO")) { /* Send .info */
- X fprintf (f, "*** Here is the info file:\n\n");
- X fclose (f);
- X cat_append (infof, mailforwardf);
- X APPEND_TELNET ("get_sys_files");
- X DELIVER_MAIL (sender, FALSE);
- X PUT_TIMESTAMP (infof, info_timestampf);
- X }
- X else if (!strcmp (file, "SUBSCRIBERS")) { /* Send .subscribers */
- X fprintf (f, "*** Here is the subscribers file:\n\n");
- X fclose (f);
- X cat_append (subscribersf, mailforwardf);
- X APPEND_TELNET ("get_sys_files");
- X DELIVER_MAIL (sender, FALSE);
- X PUT_TIMESTAMP (subscribersf, subscribers_timestampf);
- X }
- X else if (!strcmp (file, "WELCOME")) { /* Send .welcome */
- X fprintf (f, "*** Here is the welcome file:\n\n");
- X fclose (f);
- X cat_append (welcomef, mailforwardf);
- X APPEND_TELNET ("get_sys_files");
- X DELIVER_MAIL (sender, FALSE);
- X PUT_TIMESTAMP (welcomef, welcome_timestampf);
- X }
- X else if (!strcmp (file, "NEWS")) { /* Send .news */
- X fprintf (f, "*** Here is the news file:\n\n");
- X fclose (f);
- X cat_append (newsf, mailforwardf);
- X APPEND_TELNET ("get_sys_files");
- X DELIVER_MAIL (sender, FALSE);
- X PUT_TIMESTAMP (newsf, news_timestampf);
- X }
- X else if (!strcmp (file, "PEERS")) { /* Get .peers */
- X fprintf (f, "*** Here is the peers file:\n\n");
- X fclose (f);
- X cat_append (peersf, mailforwardf);
- X APPEND_TELNET ("get_sys_files");
- X DELIVER_MAIL (sender, FALSE);
- X PUT_TIMESTAMP (peersf, peers_timestampf);
- X }
- X else {
- X fprintf (f, "%s: No such file.\nFiles that can be obtained: \
- Xsubscribers/aliases/ignored/news/peers/info/welcome\n", file);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, FALSE);
- X }
- X# ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("get_sys_files", SEM_LISTFILES);
- X# endif
- X }
- X}
- X
- X/*
- X Perform various list owner requests: put user addresses in files, or
- X put new files in the list's directory. The owner may put new aliases
- X in the .aliases file, new users to be ignored in the .ignored file,
- X change the welcome message in .welcome, and change the informative
- X message in .info.
- X*/
- X
- Xvoid put (char *request, char *params, char *sender)
- X{
- X char password [MAX_LINE];
- X char keyword [MAX_LINE];
- X char arg1 [MAX_LINE];
- X char arg2 [MAX_LINE];
- X char arg3 [MAX_LINE];
- X char line [MAX_LINE];
- X char sign [MAX_LINE];
- X char params_copy [MAX_LINE];
- X BOOLEAN signature;
- X FILE *f;
- X struct stat stat_buf;
- X time_t timestamp;
- X long int sig_mask;
- X
- X arg1[0] = arg2[0] = arg3[0] = keyword[0] = params_copy[0] = RESET (password);
- X sscanf (original_params, "%s %s %s %s %s %s", password, password, keyword,
- X arg1, arg2, arg3); /* Actually only interested in arg[1-3] */
- X sscanf (params, "%s %s", password, keyword);
- X strcpy (params_copy, params);
- X shadow_password (params);
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params);
- X if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
- X NOT_LIST_OWNER; /* Hacker attack */
- X return;
- X }
- X if (password[0] == EOS) {
- X reject_mail (sender, request, "Missing password for PUT request\n\n\
- XSyntax: put <list> <password> <keyword> [args]\n\
- X\tkeyword:alias/ignore/subscribers/aliases/news/peers/ignored/info/welcome\n\
- X\targs:email address for alias/ignore\n",
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (strcmp (password, sys.lists[listid].password)) {
- X reject_mail (sender, request, "Invalid password for PUT request\n",
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X# ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("get_sys_files", SEM_LISTFILES);
- X# endif
- X if (!strcmp (keyword, "ALIAS")) { /* Add to list's, system's aliases files */
- X if (arg1[0] == EOS || arg2[0] == EOS || arg3[0] != EOS) {
- X reject_mail (sender, request, "Wrong number of arguments to \
- XPUT ... ALIAS\n\n\
- XSyntax: put <list> <password> alias <alias-address> <address-as-subscribed | \
- Xregex>\n", SYNTAX_ERROR, 0);
- X }
- X else
- X echo_append (tsprintf ("%s %s", arg1, arg2), aliasesf),
- X echo_append (tsprintf ("%s %s", arg1, arg2), ALIASESF);
- X }
- X else if (!strcmp (keyword, "IGNORE")) { /* Add to list's ignore file */
- X if (arg1[0] == EOS || arg2[0] != EOS) {
- X reject_mail (sender, request, "Wrong number of arguments to \
- XPUT ... IGNORE\n\n\
- XSyntax: put <list> <password> ignore <address>\n", SYNTAX_ERROR, 0);
- X }
- X else
- X echo_append (tsprintf ("%s", arg1), ignoredf);
- X }
- X else if (!strcmp (keyword, "WELCOME") || !strcmp (keyword, "INFO") ||
- X !strcmp (keyword, "ALIASES") || !strcmp (keyword, "IGNORED") ||
- X !strcmp (keyword, "SUBSCRIBERS") || !strcmp (keyword, "NEWS") ||
- X !strcmp (keyword, "PEERS")) {
- X if (arg1[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
- X reject_mail (sender, request,
- X tsprintf ("Too many arguments to PUT ... %s: %s\n\n\
- XSyntax: put <list> <password> <file>\n\
- X\tfile: subscribers/aliases/news/peers/ignored/info/welcome\n", keyword, arg1),
- X SYNTAX_ERROR, 0);
- X }
- X else if (!strcmp (keyword, "WELCOME")) { /* Write to .welcome */
- X CHECK_TIMESTAMP (welcome_timestampf, welcomef);
- X OPEN_FILE (f, welcomef, "w", "put");
- X unlink (welcome_timestampf);
- X }
- X else if (!strcmp (keyword, "INFO")) { /* Write to .info */
- X CHECK_TIMESTAMP (info_timestampf, infof);
- X OPEN_FILE (f, infof, "w", "put");
- X unlink (info_timestampf);
- X }
- X else if (!strcmp (keyword, "ALIASES")) { /* Write to .aliases */
- X CHECK_TIMESTAMP (aliases_timestampf, aliasesf);
- X OPEN_FILE (f, aliasesf, "w", "put");
- X unlink (aliases_timestampf);
- X }
- X else if (!strcmp (keyword, "IGNORED")) { /* Wite to .ignored */
- X CHECK_TIMESTAMP (ignored_timestampf, ignoredf);
- X OPEN_FILE (f, ignoredf, "w", "put");
- X unlink (ignored_timestampf);
- X }
- X else if (!strcmp (keyword, "SUBSCRIBERS")) { /* Write to .subscribers */
- X CHECK_TIMESTAMP (subscribers_timestampf, subscribersf);
- X OPEN_FILE (f, subscribersf, "w", "put");
- X unlink (subscribers_timestampf);
- X }
- X else if (!strcmp (keyword, "NEWS")) { /* Write to .news */
- X CHECK_TIMESTAMP (news_timestampf, newsf);
- X OPEN_FILE (f, newsf, "w", "put");
- X unlink (news_timestampf);
- X }
- X else { /* Write to .peers */
- X CHECK_TIMESTAMP (peers_timestampf, peersf);
- X OPEN_FILE (f, peersf, "w", "put");
- X unlink (peers_timestampf);
- X }
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X fflush (f);
- X COPY_MESSAGE;
- X fclose (f);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X fclose (f);
- X }
- X else {
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("put", SEM_LISTFILES);
- X#endif
- X reject_mail (sender, request, "Invalid or missing keyword for PUT \
- Xrequest\n\n\
- XSyntax: put <list> <password> <keyword> [args]\n\
- X\tkeyword:alias/ignore/subscribers/aliases/news/peers/ignored/info/welcome\n\
- X\targs:email address for alias/ignore\n", SYNTAX_ERROR, 0);
- X return;
- X }
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("put", SEM_LISTFILES);
- X#endif
- X if (!one_rejection) {
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
- X OK, FALSE, FALSE);
- X fprintf (f, "Your request was successfully completed.\n");
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, FALSE);
- X }
- X}
- X
- X/*
- X Provide help on the specified topic to 'sender'.
- X*/
- X
- Xvoid help (char *request, char *params, char *sender)
- X{
- X FILE *f, *index;
- X char param [MAX_LINE];
- X char moreparams [MAX_LINE];
- X char topic [MAX_LINE];
- X char file [MAX_LINE];
- X char shell [MAX_LINE];
- X BOOLEAN found;
- X struct stat stat_buf;
- X int ntopics;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X param[0] = RESET (moreparams);
- X sscanf (params, "%s %s\n", param, moreparams);
- X if (moreparams[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
- X reject_mail (sender, request, tsprintf ("Too many HELP topics: %s\n\n\
- XPlease separate them into multiple HELP requests.\n\n\
- XSyntax: help [topic | request]\n", moreparams),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (cchelp), OK, FALSE, FALSE);
- X if (param[0] == EOS)
- X strcpy (param, "GENERAL");
- X found = FALSE;
- X if ((index = fopen (HELP_TOPICS, "r")) == NULL)
- X fprintf (f, "Sorry, no help index found.\n");
- X else { /* Check index for help topic, get filename */
- X while (!feof (index)) {
- X topic[0] = RESET (file);
- X fscanf (index, "%s %s\n", topic, file);
- X upcase (topic);
- X if (topic[0] != EOS)
- X if (!strncmp (param, topic, strlen (param))) { /* A match */
- X found = TRUE;
- X break;
- X }
- X }
- X if (!found) {
- X fprintf (f, "Sorry, no help on topic '%s' currently available.\n\n\
- XHelp is available on the following topics:\n\n", param);
- X rewind (index);
- X ntopics = 0;
- X while (!feof (index)) {
- X topic[0] = RESET (file);
- X fscanf (index, "%s %s\n", topic, file);
- X fprintf (f, "%s ", topic);
- X if ((++ntopics) > 9)
- X ntopics = 0,
- X fprintf (f, "\n");
- X }
- X fprintf (f, "\n");
- X }
- X else if (stat (file, &stat_buf))
- X fprintf (f, "Sorry, unable to stat file %s for topic '%s'.\n", file,
- X param),
- X found = FALSE;
- X fclose (index);
- X }
- X fclose (f);
- X if (found) {
- X strcpy (shell, "cat");
- X if ((f = fopen (file, "r"))) {
- X fgets (shell, 3, f);
- X if (!strncmp (shell, "#!", 2)) {
- X fgets (shell, MAX_LINE - 2, f);
- X if (shell [strlen (shell) - 1] == '\n')
- X shell [strlen (shell) - 1] = EOS;
- X }
- X else
- X strcpy (shell, "cat");
- X fclose (f);
- X }
- X syscom ("%s %s >> %s", shell, file, mailforwardf);
- X }
- X APPEND_TELNET ("help");
- X DELIVER_MAIL (sender, COPY_OWNER (cchelp));
- X}
- X
- X/*
- X Unsubscribe a member if he/she is listed in SUBSCRIBERS. If the list
- X is remote, the request is forwarded.
- X*/
- X
- Xvoid unsubscribe (char *request, char *params, char *sender)
- X{
- X FILE *f;
- X char error [10240];
- X char param [MAX_LINE];
- X char sender_copy [MAX_LINE];
- X char address [MAX_LINE];
- X BOOLEAN status, ok_to_reset_address = FALSE, _interactive;
- X long int sig_mask;
- X int i;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X if (matched_rlists) { /* Request for a remote list; notify sender */
- X NOTIFY_OF_REQUEST_FORWARDING;
- X FORWARD_REQUEST;
- X return;
- X }
- X error[0] = RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
- X reject_mail (sender, request, tsprintf ("Invalid UNSUBSCRIBE option%s\n\
- XSyntax: unsubscribe <list> (or signoff <list>)\n", params),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (!(status = subscribed (report, sender, subscribersf, newsf, peersf,
- X aliasesf, TRUE))) {
- X if ((sys.lists[listid].defaults.set_values[0][0] == EOS &&
- X !strcmp (default_values [0], "VARIABLE")) ||
- X (!strcmp (sys.lists[listid].defaults.set_values[0], "VARIABLE")))
- X ok_to_reset_address = TRUE;
- X sprintf (error, "%s: You are not subscribed to %s\n", sender,
- X sys.lists[listid].address);
- X if (alternate_addresses) {
- X sprintf (error + strlen (error),
- X "\nIn addition, the system found the following \
- Xaddress(es) that resemble yours.\nIf one of these is you, please resend your \
- Xmessage from that one%s:\n\n",
- X (ok_to_reset_address ?
- X ", or use the\n'set <list> address' request to change the \
- Xaddress you are subscribed with" :
- X ""));
- X for (i = 0; alternate_addresses[i]; ++i)
- X sprintf (error + strlen (error), "%s\n", alternate_addresses[i]),
- X free ((char *) alternate_addresses[i]);
- X free ((char **) alternate_addresses);
- X alternate_addresses = NULL;
- X strcat (error, "\n");
- X }
- X reject_mail (sender, request, error, INVALID_REQ, 0);
- X return;
- X }
- X else if (status > SUBSCRIBED) { /* Notify manager */
- X NOTIFY_MANAGER ("Attempt to unsubscribe news or peer");
- X return;
- X }
- X /* Now move the current list of subscribers to a temporary file; then
- X copy each entry of this file to SUBSCRIBERS excluding the
- X user to be removed. */
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("unsubscribe", SEM_LISTFILES);
- X#endif
- X strcpy (sender_copy, sender);
- X escape_re (sender_copy);
- X sprintf (address, "^[\t ]*%s[ \t]", sender_copy);
- X upcase (address);
- X if (cp (subscribersf, OLD_SUBSCRIBERS))
- X gexit (16);
- X REMOVE_ADDRESS (address, OLD_SUBSCRIBERS, NEW_SUBSCRIBERS);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (mv (NEW_SUBSCRIBERS, subscribersf))
- X gexit (16);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X if (cp (aliasesf, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (mv (NEW_ALIASES, aliasesf))
- X gexit (16);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X if (cp (ALIASESF, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (mv (NEW_ALIASES, ALIASESF))
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X sprintf (address, "[ \t]%s[\t ]*$", sender_copy);
- X upcase (address);
- X if (cp (aliasesf, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (mv (NEW_ALIASES, aliasesf))
- X gexit (16);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X if (cp (ALIASESF, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (mv (NEW_ALIASES, ALIASESF))
- X gexit (16);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X unlink (OLD_SUBSCRIBERS);
- X unlink (OLD_ALIASES);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("unsubscribe", SEM_LISTFILES);
- X#endif
- X _interactive = interactive;
- X interactive = FALSE; /* Force email to sender */
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccunsub), OK, FALSE, FALSE);
- X fprintf (f, "You have been removed from list %s.\n\
- XThanks for being with us.\n", sys.lists[listid].address);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, COPY_OWNER (ccunsub));
- X interactive = _interactive;
- X if (interactive) { /* Notify ilp client */
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccsub), OK, FALSE, FALSE);
- X fprintf (f, "User %s was successfully removed from list %s.\n", sender,
- X sys.lists[listid].address);
- X fclose (f);
- X }
- X}
- X
- X/*
- X Subscribe a new user if he/she is not already subscribed. If the list
- X is remote, the request is forwarded. If the list is private, a message
- X is sent to the sender, and another one to the list owner requesting his
- X approval.
- X*/
- X
- Xvoid subscribe (char *request, char *params, char *sender, BOOLEAN override)
- X{
- X FILE *f;
- X char name [MAX_LINE];
- X char password [MAX_LINE];
- X char shell [MAX_LINE];
- X long int sig_mask;
- X int i;
- X BOOLEAN status;
- X BOOLEAN _interactive;
- X BOOLEAN live;
- X BOOLEAN chaddr;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X if (matched_rlists) { /* Request for a remote list; notify sender */
- X NOTIFY_OF_REQUEST_FORWARDING;
- X FORWARD_REQUEST;
- X return;
- X }
- X RESET (name);
- X clean_name (params); /* Remove extraneous characters */
- X sscanf (params, "%s\n", name);
- X if (name[0] == EOS) { /* No user's name */
- X reject_mail (sender, request, "No name given to SUBSCRIBE\n\n\
- XSyntax: subscribe <list> <Your Name>\n", SYNTAX_ERROR,
- X REJECT_NAME);
- X return;
- X }
- X if ((status = subscribed (report, sender, subscribersf, newsf, peersf,
- X aliasesf, TRUE)) == SUBSCRIBED) {
- X reject_mail (sender, request,
- X tsprintf ("%s: You are already subscribed to %s\n", sender,
- X sys.lists[listid].address), INVALID_REQ, 0);
- X return;
- X }
- X else if (status > SUBSCRIBED) { /* Notify manager */
- X NOTIFY_MANAGER ("Attempt to subscribe news or peer");
- X return;
- X }
- X if ((sys.lists[listid].options & NON_AUTO_SUB) &&
- X !owner_listed (OWNERSF, sender, sys.lists[listid].alias, report) &&
- X !override) { /* Notify sender/owner */
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
- X RESTRICTED_REQ, FALSE, FALSE);
- X fprintf (f, "Subscription requests are not automatic for this list. \
- XYour request has\nbeen forwarded to %s for approval.\n",
- X sys.lists[listid].owner);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, FALSE);
- X create_header (&f, mailforwardf, sys.server.address, sys.lists[listid].owner,
- X "Subscription approval request", FALSE, OK, FALSE, FALSE);
- X fprintf (f, "User %s has requested subscription to list %s\n\
- XIf you approve, send the following request to %s:\n\n\
- Xsystem %s <password> %s #%s\n\n\
- Xwhere 'password' is the list's password, as given to you by the manager of\n\
- Xthis system.\n",
- X sender, sys.lists[listid].alias, sys.server.address,
- X sys.lists[listid].alias, sender, request);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sys.lists[listid].owner, FALSE);
- X return;
- X }
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("subscribe", SEM_LISTFILES);
- X#endif
- X OPEN_FILE (f, subscribersf, "a", "subscribe"); /* Automatic subscription */
- X fprintf (f, "%s ", sender);
- X for (i = 1; i < MAX_SET_OPTIONS; i++) /* Copy all options */
- X if (sys.lists[listid].defaults.set_values[i][0] != EOS) {
- X if (i == 2)
- X strcpy (password, sys.lists[listid].defaults.set_values[i]);
- X fprintf (f, "%s ", sys.lists[listid].defaults.set_values[i]);
- X }
- X else if (i != 2) /* Not a password */
- X fprintf (f, "%s ", default_values[i]);
- X else
- X sprintf (password, "%ld", time (0)),
- X fprintf (f, "%s ", password);
- X clean_request (params); /* Remove leading blanks from name */
- X fprintf (f, "%s\n", params);
- X fclose (f);
- X REARRANGE_SUBSCRIBERS;
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("subscribe", SEM_LISTFILES);
- X#endif
- X live = (_strstr (sys.serverd_cmdoptions, "-i") != NULL);
- X _interactive = interactive;
- X interactive = FALSE; /* Force email to sender */
- X chaddr = (sys.lists[listid].defaults.set_values[0][0] == EOS &&
- X !strcmp (default_values [0], "VARIABLE")) ||
- X (!strcmp (sys.lists[listid].defaults.set_values[0], "VARIABLE"));
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccsub), OK, FALSE, FALSE);
- X fprintf (f, "You have been added to list %s.\n\
- XThe system has recorded your address as\n\n\t\t\t%s\n\n\
- Xand in order for your messages to get posted (if the list accepts postings),\n\
- Xyou will have to send them from this address, unless the list does not \
- Xrequire\nsubscription for posting.\n\
- XIf a message is ever rejected, please contact the list's owner: %s\n\n",
- X sys.lists[listid].address, sender, sys.lists[listid].owner);
- X if (live || chaddr) {
- X fprintf (f, "Your initial password is %s. Please change it as soon as you \
- Xcan\nby issuing the following request to %s:\n\n\
- X\t\tSET %s PASSWORD %s new-password\n\nWARNING: Do not use your login password; \
- Xyou will be breaching security at your\nsite.\n\n",
- X password, sys.server.address, sys.lists[listid].alias, password);
- X if (live)
- X fprintf (f, "This system may accept Internet TCP/IP connections for \
- Xprocessing of live\nrequests, and the password will be used to give you \
- Xsubscriber privileges.\nFor more information, send a 'help live' request to \
- X%s.\n\n", sys.server.address);
- X if (chaddr)
- X fprintf (f, "You may change the address you \
- Xare subscribed with (currently %s)\nwith the following request:\n\n\
- X\t\tSET %s ADDRESS %s new-address\n\nassuming that you keep the same \
- Xpassword.\n\n", sender, sys.lists[listid].alias, password);
- X }
- X fprintf (f, "For information on this service and how to use it, send the \
- Xfollowing\nrequest in the body of a mail message to %s:\n\n\t\t\tHELP\n\n\
- XAll requests should be addressed to %s.\n", sys.server.address,
- X sys.server.address);
- X fclose (f);
- X strcpy (shell, "cat");
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("subscribe", SEM_LISTFILES);
- X#endif
- X if ((f = fopen (welcomef, "r"))) {
- X fgets (shell, 3, f);
- X if (!strncmp (shell, "#!", 2)) {
- X fgets (shell, MAX_LINE - 2, f);
- X if (shell [strlen (shell) - 1] == '\n')
- X shell [strlen (shell) - 1] = EOS;
- X }
- X else
- X strcpy (shell, "cat");
- X fclose (f);
- X }
- X syscom ("%s %s >> %s", shell, welcomef, mailforwardf);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("subscribe", SEM_LISTFILES);
- X#endif
- X APPEND_TELNET ("subscribe");
- X DELIVER_MAIL (sender, COPY_OWNER (ccsub));
- X interactive = _interactive;
- X if (interactive) { /* Notify ilp client */
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccsub), OK, FALSE, FALSE);
- X fprintf (f, "User %s was successfully subscribed to list %s.\n", sender,
- X sys.lists[listid].address);
- X fclose (f);
- X }
- X}
- X
- X/*
- X Tell 'sender' what list(s) he/she is subscribed in.
- X*/
- X
- Xvoid which (char *request, char *params, char *sender)
- X{
- X char subscribersf [MAX_LINE];
- X char aliasesf [MAX_LINE];
- X char param [MAX_LINE];
- X FILE *f;
- X int i;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
- X reject_mail (sender, request, tsprintf ("Invalid WHICH option%s\n\
- XSyntax: which\n", params), SYNTAX_ERROR, 0);
- X return;
- X }
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
- X OK, FALSE, FALSE);
- X fprintf (f, "%s: You are subscribed to the following lists;\nif none appear, \
- Xyou are not subscribed to any:\n", sender);
- X for (i = 0; i < nlists; ++i) {
- X setup_string (subscribersf, sys.lists[i].alias, SUBSCRIBERS);
- X setup_string (aliasesf, sys.lists[i].alias, ALIASES);
- X if (subscribed (report, sender, subscribersf, NULL, NULL, aliasesf, TRUE) ==
- X SUBSCRIBED)
- X fprintf (f, "%s\n", sys.lists[i].alias);
- X }
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, FALSE);
- X}
- X
- X/*
- X Set options for user if he/she is subscribed. If the list is remote,
- X the request is forwarded. If resetting MAIL ACK/NOACK/POSTPONE from
- X DIGEST, send a partial digest.
- X Adding more SET options:
- X - In defs.h, define the new MAX_SET_OPTIONS.
- X - In global.h, define the new option in options[], the valid
- X values in values[] and the default_values[].
- X - the MAIL option should be second in the list; this assumption is made by
- X list and listproc.
- X*/
- X
- Xvoid set (char *request, char *params, char *sender)
- X{
- X FILE *f, *from, *to;
- X char error [10240];
- X char option [MAX_LINE];
- X char subscriber [MAX_LINE];
- X char oldmodes [MAX_SET_OPTIONS] [MAX_LINE];
- X char newmode [MAX_LINE];
- X char moreparams [MAX_LINE];
- X char name [MAX_LINE];
- X char address [MAX_LINE];
- X char *blank;
- X int i, j, index;
- X long int sig_mask;
- X BOOLEAN status, ok_to_reset_address = FALSE;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X error[0] = option[0] = moreparams[0] = RESET (newmode);
- X sscanf (params, "%s %s %s\n", option, newmode, moreparams); /* Get params */
- X upcase (option);
- X upcase (newmode);
- X if (matched_rlists) { /* Request for a remote list; notify sender */
- X NOTIFY_OF_REQUEST_FORWARDING;
- X FORWARD_REQUEST;
- X return;
- X }
- X if ((sys.lists[listid].defaults.set_values[0][0] == EOS &&
- X !strcmp (default_values [0], "VARIABLE")) ||
- X (!strcmp (sys.lists[listid].defaults.set_values[0], "VARIABLE")))
- X ok_to_reset_address = TRUE;
- X if (!(status = subscribed (report, sender, subscribersf, newsf, peersf,
- X aliasesf, TRUE))) {
- X sprintf (error, "%s: You are not subscribed to %s\n", sender,
- X sys.lists[listid].address);
- X if (alternate_addresses) {
- X sprintf (error + strlen (error),
- X "\nIn addition, the system found the following \
- Xaddress(es) that resemble yours.\nIf one of these is you, please resend your \
- Xmessage from that one%s:\n\n",
- X (ok_to_reset_address ?
- X ", or use the\n'set <list> address' request to change the \
- Xaddress you are subscribed with" :
- X ""));
- X for (i = 0; alternate_addresses[i]; ++i)
- X sprintf (error + strlen (error), "%s\n", alternate_addresses[i]),
- X free ((char *) alternate_addresses[i]);
- X free ((char **) alternate_addresses);
- X alternate_addresses = NULL;
- X strcat (error, "\n");
- X }
- X reject_mail (sender, request, error, INVALID_REQ, 0);
- X return;
- X }
- X else if (status > SUBSCRIBED) { /* Notify manager */
- X NOTIFY_MANAGER ("Attempt to set mode for news or peer");
- X return;
- X }
- X if (option[0] != EOS) {
- X for (index = 0; index < MAX_SET_OPTIONS; index++)
- X if (! strcmp (option, options[index]))
- X break;
- X if (index == MAX_SET_OPTIONS) {
- X reject_mail (sender, request, tsprintf ("Invalid SET option %s\n\n\
- XSyntax: set <list> [<option> <arg[s]>]\n\
- X\toption: mail, password, address, conceal\n\
- X\targ for 'mail': ack/noack/postpone/digest\n\
- X\targs for 'password': <current-password> <new-password>\n\
- X\targs for 'address': <current-password> <new-address>\n\
- X\targ for 'conceal': yes/no\n", option), SYNTAX_ERROR, 0);
- X return;
- X }
- X if (newmode[0] == EOS ||
- X (!strcmp (option, options[0]) && moreparams[0] == EOS) ||
- X (!strcmp (option, options[2]) && moreparams[0] == EOS)) {
- X reject_mail (sender, request, tsprintf ("Missing SET %s value\n\n\
- XSyntax: set <list> [<option> <arg[s]>]\n\
- X\toption: mail, password, address, conceal\n\
- X\targ for 'mail': ack/noack/postpone/digest\n\
- X\targs for 'password': <current-password> <new-password>\n\
- X\targs for 'address': <current-password> <new-address>\n\
- X\targ for 'conceal': yes/no\n", options[index]), SYNTAX_ERROR, 0);
- X return;
- X }
- X if (index > 0 &&
- X !strinstr (values[index], (index == 1 || index == 3 ?
- X newmode : moreparams))) {
- X reject_mail (sender, request, tsprintf ("Invalid SET %s value %s\n\n\
- XSyntax: set <list> [<option> <arg[s]>]\n\
- X\toption: mail, password, address, conceal\n\
- X\targ for 'mail': ack/noack/postpone/digest\n\
- X\targs for 'password': <current-password> <new-password>\n\
- X\targs for 'address': <current-password> <new-address>\n\
- X\targ for 'conceal': yes/no\n", options[index], newmode), SYNTAX_ERROR, 0);
- X return;
- X }
- X }
- X if (moreparams[0] != EOS && strcmp (option, options[0]) &&
- X strcmp (option, options[2]) && !(sys.options & RELAXED_SYNTAX)) {
- X reject_mail (sender, request, tsprintf ("Too many SET parameters: %s\n\n\
- XSyntax: set <list> [<option> <arg[s]>]\n\
- X\toption: mail, password, address, conceal\n\
- X\targ for 'mail': ack/noack/postpone/digest\n\
- X\targs for 'password': <current-password> <new-password>\n\
- X\targs for 'address': <current-password> <new-address>\n\
- X\targ for 'conceal': yes/no\n", moreparams), SYNTAX_ERROR, 0);
- X return;
- X }
- X if (option[0] == EOS) { /* Status inquiry */
- X if (! one_rejection) {
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("set", SEM_LISTFILES);
- X#endif
- X#if defined (__NeXT__) || defined (__convex__) || defined (unknown_port)
- X syscom ("grep -i '^[ \t]*%s ' %s | \
- X%s '{ printf \"%%s\", $1; for (i = 2; i <= %d; ++i) printf \" %%s\", $i; \
- Xprintf \"\\n\" }' > %s",
- X sender, subscribersf, AWK, MAX_SET_OPTIONS, OLD_SUBSCRIBERS);
- X#else
- X syscom ("grep -i '^[ \t]*%s ' %s | %s -d' ' -f1-%d > %s", sender,
- X subscribersf, CUT, MAX_SET_OPTIONS, OLD_SUBSCRIBERS);
- X#endif
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccset), OK, FALSE, FALSE);
- X fprintf (f, "Current settings are:\n\n");
- X OPEN_FILE (from, OLD_SUBSCRIBERS, "r", "set");
- X for (i = 0; i < MAX_SET_OPTIONS; i++)
- X RESET (newmode),
- X fscanf (from, "%s ", newmode),
- X fprintf (f, "%s = %s\n", options[i], newmode);
- X fflush (f);
- X fclose (from);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("set", SEM_LISTFILES);
- X#endif
- X DELIVER_MAIL (sender, COPY_OWNER (ccset));
- X unlink (OLD_SUBSCRIBERS);
- X }
- X return;
- X }
- X /* Change of mode */
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("set", SEM_LISTFILES);
- X#endif
- X if (cp (subscribersf, OLD_SUBSCRIBERS))
- X gexit (16);
- X OPEN_FILE (from, OLD_SUBSCRIBERS, "r", "set");
- X OPEN_FILE (to, NEW_SUBSCRIBERS, "w", "set");
- X while (!feof (from)) {
- X subscriber[0] = RESET (name);
- X if (!extract_subscriber (from, subscriber, FALSE)) {
- X NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS (subscriber);
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccset), OK, FALSE, FALSE);
- X fprintf (f, "Sorry, a system error has occured. Try again later.\n");
- X COMPLETE_TELNET (f);
- X fclose (f);
- X fclose (from);
- X fclose (to);
- X unlink (OLD_SUBSCRIBERS);
- X unlink (NEW_SUBSCRIBERS);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("set", SEM_LISTFILES);
- X#endif
- X DELIVER_MAIL (sender, COPY_OWNER (ccset));
- X return;
- X }
- X strcpy (oldmodes[0], subscriber);
- X for (i = 1; i < MAX_SET_OPTIONS; i++)
- X RESET (oldmodes[i]),
- X fscanf (from, "%s ", oldmodes[i]);
- X fgets (name, MAX_LINE - 2, from);
- X upcase (subscriber);
- X if (!feof (from)) {
- X if (! strcmp (sender, subscriber))
- X for (i = 0; i < MAX_SET_OPTIONS; i++) {
- X if (i == 0) {
- X if (!strcmp (option, options[0]))
- X if (!ok_to_reset_address)
- X fprintf (to, "%s ", subscriber),
- X reject_mail (sender, request, "Changing of address is not \
- Xallowed for this list.\n", RESTRICTED_REQ, 0);
- X else
- X if (strcmp (newmode, oldmodes[2])) /* Invalid password */
- X fprintf (to, "%s ", subscriber),
- X reject_mail (sender, request,
- X tsprintf ("Password verification failure: %s\n",
- X newmode), SYNTAX_ERROR, 0);
- X else {
- X sprintf (address, "From %s", moreparams);
- X if (!extract_sender (address))
- X fprintf (to, "%s ", subscriber),
- X reject_mail (sender, request,
- X tsprintf ("Invalid address: %s\n", moreparams),
- X SYNTAX_ERROR, 0);
- X else {
- X sprintf (address, "^[\t ]*%s ", sender);
- X if (cp (aliasesf, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (mv (NEW_ALIASES, aliasesf))
- X gexit (16);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X if (cp (ALIASESF, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (mv (NEW_ALIASES, ALIASESF))
- X gexit (16);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X sprintf (address, " %s[\t ]*$", sender);
- X if (cp (aliasesf, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (mv (NEW_ALIASES, aliasesf))
- X gexit (16);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X if (cp (ALIASESF, OLD_ALIASES))
- X gexit (16);
- X REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (mv (NEW_ALIASES, ALIASESF))
- X gexit (16);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X unlink (OLD_ALIASES);
- X if (echo_append (tsprintf ("%s %s", subscriber,
- X moreparams), aliasesf))
- X gexit (16);
- X if (echo_append (tsprintf ("%s %s", subscriber,
- X moreparams), ALIASESF))
- X gexit (16);
- X fprintf (to, "%s ", moreparams); /* Put new address */
- X }
- X }
- X else
- X fprintf (to, "%s ", subscriber);
- X }
- X else if (i == 2 && !strcmp (option, options[2]) &&
- X strcmp (newmode, oldmodes[i])) /* Invalid old password */
- X fprintf (to, "%s ", oldmodes[i]),
- X reject_mail (sender, request,
- X tsprintf ("Password verification failure: %s\n", newmode),
- X SYNTAX_ERROR, 0);
- X else
- X fprintf (to, "%s ", (i == index ?
- X (strcmp (option, options[2]) ? newmode : moreparams) :
- X oldmodes[i]));
- X if (strcmp (newmode, DIGEST) && strcmp (newmode, POSTPONE) &&
- X !strcmp (oldmodes[i], DIGEST))
- X /* Turned off DIGEST, send a partial digest */
- X syscom ("%s %s -i%s %s", LIST, sys.lists[listid].alias,
- X sender, sys.lists[i].cmdoptions);
- X }
- X else
- X for (i = 0; i < MAX_SET_OPTIONS; i++)
- X fprintf (to, "%s ", oldmodes[i]);
- X clean_request (name); /* Remove leading blanks */
- X fprintf (to, "%s", name);
- X }
- X }
- X fclose (from);
- X fclose (to);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (mv (NEW_SUBSCRIBERS, subscribersf))
- X gexit (16);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X unlink (OLD_SUBSCRIBERS);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("set", SEM_LISTFILES);
- X#endif
- X if (! one_rejection) {
- X blank = request;
- X (index == 0 ? (j = 3) : (j = 4));
- X for (i = 0; i < j; i++)
- X blank = strchr (blank + 1, ' ');
- X ++blank;
- X shadow_password (blank);
- X create_header (&f, mailforwardf, sys.server.address,
- X (index == 0 ? moreparams : sender), request,
- X COPY_OWNER (ccset), OK, FALSE, FALSE);
- X fprintf (f, "%s mode reset to %s\n", options[index],
- X (index == 0 || index == 2 ? moreparams : newmode));
- X COMPLETE_TELNET (f);
- X fclose (f);
- X if (!index) {
- X DELIVER_MAIL (moreparams, COPY_OWNER (ccset));
- X }
- X else
- X DELIVER_MAIL (sender, COPY_OWNER (ccset));
- X }
- X}
- X
- X/*
- X Provide user with the current list of subscribers. Peer servers are
- X also notified and they send their own compilations. If the list is
- X remote, the request is forwarded.
- X For private lists, only members may make this request.
- X*/
- X
- Xvoid recipients (char *request, char *params, char *sender)
- X{
- X char param [MAX_LINE];
- X FILE *f;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X if (matched_rlists) { /* Request for a remote list; notify sender */
- X NOTIFY_OF_REQUEST_FORWARDING;
- X FORWARD_REQUEST;
- X return;
- X }
- X RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
- X reject_mail (sender, request, tsprintf ("Invalid RECIPIENTS option%s\n\
- XSyntax: recipients <list> (or review <list>)\n", params), SYNTAX_ERROR, 0);
- X return;
- X }
- X if (sys.lists[listid].options & NON_AUTO_SUB) { /* Private list */
- X if (subscribed (report, sender, subscribersf, NULL, NULL, aliasesf, TRUE) ==
- X NOTSUBSCRIBED) {
- X MEMBERS_ONLY;
- X return;
- X }
- X }
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccrec), OK, FALSE, FALSE);
- X fprintf (f, "Here is the current list of non-concealed subscribers:\n\n");
- X fclose (f);
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("recipients", SEM_LISTFILES);
- X#endif
- X#if defined (__NeXT__) || defined (__convex__) || defined (unknown_port)
- X syscom ("%s '{ printf \"%%s\", $1; for (i = %d; i <= %d; ++i) \
- Xprintf \" %%s\", $i; printf \"\\n\" }' %s | grep -i ' NO ' | \
- X%s '{ printf \"%%s\", $1; for (i = 3; i <= %d; ++i) printf \" %%s\", $i; \
- Xprintf \"\\n\" }' > %s",
- X AWK, MAX_SET_OPTIONS, MAX_SET_OPTIONS + 5, subscribersf, AWK,
- X MAX_SET_OPTIONS + 4, recipf);
- X#else
- X syscom ("%s -d\" \" -f1,%d-%d %s | grep -i ' NO ' | %s -d\" \" -f1,3-%d \
- X> %s", CUT, MAX_SET_OPTIONS, MAX_SET_OPTIONS + 5, subscribersf, CUT,
- X MAX_SET_OPTIONS + 4, recipf);
- X#endif
- X syscom ("%s -f %s %s >> %s", AWK, AWK_PROG, recipf, mailforwardf);
- X syscom ("echo Total number of subscribers: `cat %s | wc -l` \
- X\"(`cat %s | wc -l | tr -d ' '` shown here)\" >> %s", subscribersf, recipf,
- X mailforwardf);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("recipients", SEM_LISTFILES);
- X#endif
- X unlink (recipf);
- X APPEND_TELNET ("recipients");
- X DELIVER_MAIL (sender, COPY_OWNER (ccrec));
- X notify_peer_servers (peersf, "review", params, sender);
- X}
- X
- X/*
- X Provide user with general information about the list. A reminder, the
- X actual text is in the INFO_FILE. If the list is remote, the request
- X is forwarded.
- X*/
- X
- Xvoid info (char *request, char *params, char *sender)
- X{
- X char param [MAX_LINE];
- X char shell [MAX_LINE];
- X FILE *f;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X if (matched_rlists) { /* Request for a remote list; notify sender */
- X NOTIFY_OF_REQUEST_FORWARDING;
- X FORWARD_REQUEST;
- X return;
- X }
- X RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
- X reject_mail (sender, request, tsprintf ("Invalid INFORMATION option%s\n\
- XSyntax: information <list>\n", params), SYNTAX_ERROR, 0);
- X return;
- X }
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccinfo), OK, FALSE, FALSE);
- X fclose (f);
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("info", SEM_LISTFILES);
- X#endif
- X strcpy (shell, "cat");
- X if ((f = fopen (infof, "r"))) {
- X fgets (shell, 3, f);
- X if (!strncmp (shell, "#!", 2)) {
- X fgets (shell, MAX_LINE - 2, f);
- X if (shell [strlen (shell) - 1] == '\n')
- X shell [strlen (shell) - 1] = EOS;
- X }
- X else
- X strcpy (shell, "cat");
- X fclose (f);
- X }
- X syscom ("%s %s >> %s", shell, infof, mailforwardf);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("info", SEM_LISTFILES);
- X#endif
- X APPEND_TELNET ("info");
- X DELIVER_MAIL (sender, COPY_OWNER (ccinfo));
- X}
- X
- X/*
- X Collect and send statistics about all subscribers, by grepping through
- X HEADERS. If a user has selected particular names (asterisks are OK) then
- X give statistics about these people only. Also include a total count
- X of messages on file. Peer servers are also notified and they send their
- X own compilations. If the list is remote, the request is forwarded.
- X For private lists, only members may make this request.
- X*/
- X
- Xvoid stats (char *request, char *params, char *sender)
- X{
- X FILE *f;
- X char junk [MAX_LINE];
- X struct stat stat_buf;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X if (matched_rlists) { /* Request for a remote list; notify sender */
- X NOTIFY_OF_REQUEST_FORWARDING;
- X FORWARD_REQUEST;
- X return;
- X }
- X if (sys.lists[listid].options & NON_AUTO_SUB) { /* Private list */
- X if (subscribed (report, sender, subscribersf, NULL, NULL, aliasesf, TRUE) ==
- X NOTSUBSCRIBED) {
- X MEMBERS_ONLY;
- X return;
- X }
- X }
- X params [strlen (params) - 1] = EOS; /* Remove \n */
- X RESET (junk);
- X sscanf (params, "%s", junk);
- X if (junk[0] == EOS) /* No specific subscribers to report on */
- X RESET (params);
- X if (stat (headersf, &stat_buf)) {
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, no mail archive found.\n", NULL, OK);
- X return;
- X }
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccstat), OK, FALSE, FALSE);
- X fprintf (f, "Here are the number of messages per non-concealed subscriber:\
- X\n\n");
- X fclose (f);
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("stats", SEM_LISTFILES);
- X#endif
- X EXEC_STATS;
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("stats", SEM_LISTFILES);
- X#endif
- X APPEND_TELNET ("stats");
- X DELIVER_MAIL (sender, COPY_OWNER (ccstat));
- X notify_peer_servers (peersf, "stat", params, sender);
- X}
- X
- X/*
- X Exit with a shutdown status if the correct password is provided.
- X*/
- X
- Xvoid Shutdown (char *request, char *params, char *sender)
- X{
- X char passwd [MAX_LINE];
- X
- X sscanf (params, "%s\n", passwd);
- X if (!strcmp (sys.server.password, passwd))
- X report_progress (report, "SHUTDOWN request accepted", TRUE),
- X gexit (6); /* Exit status of 6 signifies a shutdown request */
- X reject_mail (sender, request, tsprintf ("Unrecognized request %s\n", request),
- X INVALID_REQ, 0);
- X}
- X
- X/*
- X Set the global variable 'restart_sys' to TRUE if the correct password
- X is given.
- X*/
- X
- Xvoid restart (char *request, char *params, char *sender)
- X{
- X char passwd [MAX_LINE];
- X
- X sscanf (params, "%s\n", passwd);
- X if (!strcmp (sys.server.password, passwd)) {
- X report_progress (report, "RESTART request accepted\n", FALSE);
- X restart_sys = TRUE;
- X return;
- X }
- X reject_mail (sender, request, tsprintf ("Unrecognized request %s\n", request),
- X INVALID_REQ, 0);
- X}
- X
- X/*
- X Provide 'sender' with a list of all mailing lists served by this server,
- X as well as any remote lists known to this server.
- X*/
- X
- Xvoid lists (char *request, char *params, char *sender)
- X{
- X char param [MAX_LINE];
- X FILE *f;
- X int i, alslen, lstlen, adrlen, len, _nlists;
- X REMOTE *r = rlists, *s = rlists;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
- X reject_mail (sender, request, tsprintf ("Invalid LISTS option%s\n\
- XSyntax: lists\n", params), SYNTAX_ERROR, 0);
- X return;
- X }
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (cclists), OK, FALSE, FALSE);
- X adrlen = -99;
- X for (i = 0, _nlists = 0; i < nlists; ++i) /* Get longest address */
- X if (!(sys.lists[i].options & CONCEAL_LIST)) {
- X ++_nlists;
- X if ((len = strlen (sys.lists[i].address)) > adrlen)
- X adrlen = len;
- X }
- X fprintf (f, "Here is the current active list of the %d mailing lists \
- Xserved by this server:\n\n", _nlists);
- X for (i = 0; i < nlists; ++i)
- X if (!(sys.lists[i].options & CONCEAL_LIST))
- X fprintf (f, "%-*s %s\n", adrlen, sys.lists[i].address,
- X sys.lists[i].comment);
- X
- X if (rlists) { /* List all remote lists */
- X i = 0;
- X fprintf (f, "\nIn addition, the following remote lists are known to this \
- Xserver:\n\n");
- X alslen = strlen ("ALIAS");
- X adrlen = strlen ("FULL ADDRESS");
- X lstlen = strlen ("LISTPROCESSOR ADDRESS");
- X while (s) {
- X if ((len = strlen (s->alias)) > alslen)
- X alslen = len;
- X if ((len = strlen (s->address)) > adrlen)
- X adrlen = len;
- X if ((len = strlen (s->listproc)) > lstlen)
- X lstlen = len;
- X s = s->next;
- X }
- X fprintf (f, "%-*s %-*s %-*s COMMENT\n%-*s %-*s %-*s -------\n",
- X alslen, "ALIAS", adrlen, "FULL ADDRESS", lstlen, "LISTPROCESSOR ADDRESS",
- X alslen, "-----", adrlen, "------------", lstlen, "---------------------");
- X while (r)
- X ++i,
- X fprintf (f, "%-*s %-*s %-*s %s\n", alslen, r->alias, adrlen,
- X r->address, lstlen, r->listproc, r->comment),
- X r = r->next;
- X fprintf (f, "\nTotal number of remote lists: %d. Requests sent to \
- Xthis server for these\nremote lists will be forwarded to the servers \
- Xserving these lists.\n", i);
- X }
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, COPY_OWNER (cclists));
- X}
- X
- X/*
- X Get an index of files for the specified archive, or the master archive
- X if none specified. Private archives require a password to list their
- X files.
- X
- X Adapted USER CONTRIBUTED FUNCTION: Stefan Schroer.
- X*/
- X
- Xvoid Index (char *request, char *params, char *sender)
- X{
- X FILE *f, *index, *dir, *master;
- X char archive [MAX_LINE];
- X char arch [MAX_LINE];
- X char cur_archive [MAX_LINE];
- X char line [MAX_LINE];
- X char file [MAX_LINE];
- X char fullpath [MAX_LINE];
- X char moreparams [MAX_LINE];
- X char fullname [MAX_LINE];
- X char desc [MAX_LINE];
- X char junk [MAX_LINE];
- X char user_password [MAX_LINE];
- X char sys_password [MAX_LINE];
- X char *slash;
- X BOOLEAN found, continued, header_printed, all = FALSE;
- X int count, parts, i;
- X long int *filesizes;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X archive[0] = fullpath[0] = fullname[0] =
- X cur_archive[0] = RESET (moreparams);
- X sscanf (params, "%s %s %s", archive, user_password, moreparams);
- X if (archive[0] == '/') /* No archive given, just password */
- X strcpy (user_password, archive),
- X RESET (archive);
- X else if (!strcmp (archive, "-ALL"))
- X all = TRUE,
- X RESET (archive);
- X if (user_password[0] == '/') /* Remove leading '/' */
- X sprintf (user_password, "%s", user_password + 1);
- X else if (!strcmp (user_password, "-ALL"))
- X RESET (user_password),
- X all = TRUE;
- X locase (archive);
- X if (moreparams[0] != EOS)
- X if (strcmp (moreparams, "-ALL")) {
- X if (!(sys.options & RELAXED_SYNTAX)) {
- X reject_mail (sender, request,
- X tsprintf ("Too many arguments to INDEX: %s\n\n\
- XSyntax: index [archive | path-to-archive] [/password]\n", moreparams),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X }
- X else
- X all = TRUE;
- X if (archive[0] == EOS) /* Get archive */
- X strcpy (archive, DEFAULT_ARCHIVE);
- X sprintf (fullpath, "%s/%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE, INDEX);
- X strcpy (cur_archive, archive);
- X if ((slash = strchr (cur_archive, '/')))
- X *slash = EOS;
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("Index", SEM_ARCHIVES);
- X#endif
- X while (archive[0] != EOS) { /* Check all archives specified */
- X if ((master = fopen (fullpath, "r")) == NULL) {
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("Index", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("%s: Sorry, no index found.\n", cur_archive,
- X BAD_ARCHIVE);
- X return;
- X }
- X found = FALSE;
- X while (!feof (master)) { /* Look at the current index for fullpath */
- X fullpath[0] = arch[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, master);
- X if (line[0] != EOS) {
- X sscanf (line, "%s %s\n", arch, fullpath);
- X locase (arch);
- X if (!strcmp (arch, cur_archive)) {
- X found = TRUE;
- X break;
- X }
- X }
- X }
- X fclose (master);
- X if (!found) {
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("Index", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("%s: not a valid archive or path.\n", cur_archive,
- X SYNTAX_ERROR);
- X return;
- X }
- X if ((slash = strchr (archive, '/')))
- X sprintf (archive, "%s", slash + 1); /* Move down the path */
- X else
- X sprintf (archive, "%s", archive + strlen (cur_archive));
- X strcpy (cur_archive, archive);
- X if ((slash = strchr (cur_archive, '/')))
- X *slash = EOS;
- X if (cur_archive[0] != EOS)
- X sprintf (fullpath, "%s/%s", fullpath, INDEX);
- X }
- X sscanf (params, "%s", archive);
- X sprintf (fullname, "%s/%s", fullpath, INDEX);
- X if ((index = fopen (fullname, "r")) == NULL) { /* Open index */
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("Index", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, no index found in archive %s.\n", archive,
- X BAD_ARCHIVE);
- X return;
- X }
- X slash = request;
- X while ((slash = strchr (slash + 1, '/')) && !isspace (*(slash - 1)));
- X if (slash)
- X shadow_password (slash + 1);
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccindex), OK, FALSE, FALSE);
- X count = 0;
- X while (!feof (index)) { /* Echo archive; goto archive and get DIR file */
- X fullpath[0] = archive[0] = sys_password[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, index);
- X if (line[0] != EOS) {
- X sscanf (line, "%s %s %s\n", archive, fullpath, sys_password);
- X upcase (sys_password);
- X fprintf (f, "\n%s: %s ", (!count ? "Archive" : "Subarchive"), archive);
- X if (!strncmp (fullpath, ARCHIVE_DIR, strlen (ARCHIVE_DIR)))
- X fprintf (f, "(path: %s) ", fullpath + strlen (ARCHIVE_DIR) + 1);
- X if (!count || all) { /* List files for the top level archive only */
- X fprintf (f, "-- Files:\n");
- X if (sys_password[0] != EOS && strcmp (user_password, sys_password)) {
- X reply_code (RESTRICTED_REQ);
- X fprintf (f, "This archive requires special privileges for access.\n");
- X continue;
- X }
- X if (chdir (fullpath))
- X fprintf (f, "%s: Sorry, archive out of date.\n", archive);
- X else { /* Open DIR and get file names */
- X if ((dir = fopen (DIRF, "r")) == NULL)
- X reply_code (BAD_ARCHIVE),
- X fprintf (f, "Cannot obtain directory information.\n");
- X else {
- X while (!feof (dir)) {
- X line[0] = junk[0] = RESET (file);
- X fscanf (dir, "%s %d ", file, &parts);
- X if (file[0] != EOS) {
- X if (! (filesizes = (long int *) malloc (abs (parts) * sizeof (long int))))
- X report_progress (report, "\nIndex(): malloc() failed", TRUE),
- X gexit (11);
- X for (i = 0; i < abs (parts); i++)
- X fscanf (dir, "%ld ", filesizes + i);
- X fscanf (dir, "%s", junk);
- X header_printed = FALSE;
- X do { /* Get file description */
- X RESET (desc);
- X fgets (desc, MAX_LINE - 2, dir);
- X if (desc [0] != EOS && desc[strlen (desc) - 1] == '\n')
- X desc[strlen (desc) - 1] = EOS;
- X continued = FALSE;
- X if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
- X desc[strlen (desc) - 1] = EOS,
- X continued = TRUE;
- X if (file[0] != EOS) {
- X if (!header_printed) {
- X fprintf (f, " %s (%d part%s", file, abs (parts),
- X (abs (parts) > 1 ? "s" : ""));
- X for (i = 0; i < abs (parts); i++)
- X fprintf (f, ", %ld", *(filesizes + i));
- X fprintf (f, " bytes) %s", ((desc[0] != EOS) ? "--" : ""));
- X free ((long int *) filesizes);
- X header_printed = TRUE;
- X }
- X fprintf (f, "%s\n", desc);
- X }
- X } while (continued);
- X }
- X }
- X fclose (dir);
- X }
- X }
- X }
- X else
- X fprintf (f, "\n");
- X }
- X ++count;
- X }
- X fclose (index);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("Index", SEM_ARCHIVES);
- X#endif
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, COPY_OWNER (ccindex));
- X}
- X
- X/*
- X Send the requested file from the specified archive. The file may have been
- X split in subparts, and in this case several emails will be sent -- one
- X for each part. The user may also obtain certain parts. A password is
- X required for obtaining files from a private archive.
- X
- X Adapted USER CONTRIBUTED FUNCTION: Stefan Schroer.
- X*/
- X
- Xvoid get (char *request, char *params, char *sender)
- X{
- X FILE *f, *dir, *master;
- X char archive [MAX_LINE];
- X char arch [MAX_LINE];
- X char cur_archive [MAX_LINE];
- X char archive_orig [MAX_LINE];
- X char fullpath [MAX_LINE];
- X char moreparams [MAX_LINE];
- X char filename [MAX_LINE];
- X char fullname [MAX_LINE];
- X char dirpath [MAX_LINE];
- X char file [MAX_LINE];
- X char line [MAX_LINE];
- X char copy [MAX_LINE];
- X char sys_password [MAX_LINE];
- X char user_password [MAX_LINE];
- X char desc [MAX_LINE];
- X char subject [MAX_LINE];
- X char req [MAX_LINE];
- X char *slash, *uue_file = NULL, *s;
- X struct stat stat_buf;
- X int i, count = 0;
- X long int *filesizes;
- X BOOLEAN found, continued, compressed_source;
- X
- X strcpy (req, request);
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X archive[0] = fullpath[0] = fullname[0] = dirpath[0] =
- X filename[0] = cur_archive[0] = archive_orig[0] = sys.fax.fax_no [0] =
- X RESET (moreparams);
- X params [strlen (params) - 1] = EOS; /* Remove \n */
- X if (!strcmp (req, "FAX"))
- X fax_it = TRUE,
- X sscanf (params, "%s %s %s %s", sys.fax.fax_no, archive, filename,
- X moreparams);
- X else
- X fax_it = FALSE,
- X sscanf (params, "%s %s %s", archive, filename, moreparams);
- X strcpy (archive_orig, archive);
- X locase (archive);
- X locase (filename);
- X if (archive[0] == EOS || filename[0] == EOS ||
- X (fax_it && sys.fax.fax_no[0] == EOS)) { /* Missing args */
- X reject_mail (sender, request, tsprintf ("%s: missing arguments\n\n\
- XSyntax: %s %s<archive | path-to-archive> <file> [/password] [parts]\n", req,
- X req, (fax_it ? "<fax-number> " : "")), SYNTAX_ERROR, 0);
- X fax_it = FALSE;
- X return;
- X }
- X if (moreparams[0] != EOS) { /* Specified password and/or parts to get */
- X if (moreparams[0] == '/') { /* Get password and any parts */
- X strcpy (user_password, moreparams);
- X strcpy (copy, user_password);
- X upcase (copy);
- X do {
- X sprintf (params, "%s", params + 1);
- X } while (strncmp (params, copy, strlen (copy)));
- X sprintf (params, "%s", params + strlen (copy));
- X RESET (moreparams);
- X sscanf (params, "%s", moreparams); /* Get parts */
- X if (moreparams[0] != EOS)
- X sprintf (params, "%s", strchr (params, moreparams[0]));
- X if (user_password[0] == '/') /* Remove leading '/' */
- X sprintf (user_password, "%s", user_password + 1);
- X }
- X else { /* No password given just parts */
- X strcpy (copy, filename);
- X upcase (copy);
- X do {
- X sprintf (params, "%s", params + 1);
- X } while (strncmp (params, copy, strlen (copy)));
- X sprintf (params, "%s", params + strlen (copy));
- X sprintf (params, "%s", strchr (params, moreparams[0]));
- X }
- X }
- X sprintf (fullpath, "%s/%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE, INDEX);
- X strcpy (cur_archive, archive);
- X if ((slash = strchr (cur_archive, '/')))
- X *slash = EOS;
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("get", SEM_ARCHIVES);
- X#endif
- X while (archive[0] != EOS) { /* Check all archives specified */
- X if ((master = fopen (fullpath, "r")) == NULL) {
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("%s: Sorry, no index found.\n", cur_archive,
- X BAD_ARCHIVE);
- X fax_it = FALSE;
- X return;
- X }
- X found = FALSE;
- X while (!feof (master)) { /* Look at the current index for fullpath */
- X fullpath[0] = arch[0] = sys_password[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, master);
- X if (line[0] != EOS) {
- X sscanf (line, "%s %s %s\n", arch, fullpath, sys_password);
- X locase (arch);
- X upcase (sys_password);
- X if (!strcmp (arch, cur_archive)) {
- X found = TRUE;
- X break;
- X }
- X }
- X }
- X fclose (master);
- X if (!found) {
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("%s: not a valid archive or path.\n", cur_archive,
- X SYNTAX_ERROR);
- X fax_it = FALSE;
- X return;
- X }
- X if ((slash = strchr (archive, '/')))
- X sprintf (archive, "%s", slash + 1); /* Move down the path */
- X else
- X sprintf (archive, "%s", archive + strlen (cur_archive));
- X strcpy (cur_archive, archive);
- X if ((slash = strchr (cur_archive, '/')))
- X *slash = EOS;
- X if (cur_archive[0] != EOS)
- X sprintf (fullpath, "%s/%s", fullpath, INDEX);
- X }
- X
- X
- X if (sys_password[0] != EOS && strcmp (user_password, sys_password)) {
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, archive %s requires special privileges \
- Xfor obtaining files.\n", archive_orig, RESTRICTED_REQ);
- X fax_it = FALSE;
- X return;
- X }
- X sprintf (dirpath, "%s/%s", fullpath, DIRF);
- X if ((dir = fopen (dirpath, "r")) == NULL) { /* Dir archive */
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("Unable to dir archive %s\n", archive_orig,
- X BAD_ARCHIVE);
- X fax_it = FALSE;
- X return;
- X }
- X found = FALSE;
- X while (!feof (dir)) { /* Get location and file-count of file to send */
- X file[0] = RESET (fullpath);
- X fscanf (dir, "%s %d ", file, &count);
- X if (! (filesizes = (long int *) malloc (abs (count) * sizeof (long int))))
- X report_progress (report, "\nget(): malloc() failed", TRUE),
- X gexit (11);
- X for (i = 0; i < abs (count); i++)
- X fscanf (dir, "%ld ", filesizes + i);
- X fscanf (dir, "%s", fullpath);
- X do { /* Get file description */
- X RESET (desc);
- X fgets (desc, MAX_LINE - 2, dir);
- X if (desc[0] != EOS && desc[strlen (desc) - 1] == '\n')
- X desc[strlen (desc) - 1] = EOS;
- X continued = FALSE;
- X if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
- X desc[strlen (desc) - 1] = EOS,
- X continued = TRUE;
- X } while (continued);
- X if (file[0] != EOS) {
- X locase (file);
- X if (!strcmp (filename, file)) {
- X found = TRUE;
- X break;
- X }
- X }
- X }
- X fclose (dir);
- X if (!found) {
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, file %s not found in specified archive.\n",
- X filename, SYNTAX_ERROR);
- X fax_it = FALSE;
- X return;
- X }
- X if (interactive) /* Empty out file */
- X create_header (&f, mailforwardf, sys.server.address, sender, subject,
- X COPY_OWNER (ccget), OK, FALSE, FALSE),
- X fclose (f);
- X for (i = 1; i <= abs (count); i++) { /* Send all parts of the file */
- X RESET (fullname);
- X if (abs (count) > 1)
- X sprintf (fullname, "%s/%s%d", fullpath, filename, i);
- X else
- X sprintf (fullname, "%s/%s", fullpath, filename);
- X if (moreparams[0] != EOS && !requested_part (params, i))
- X continue;
- X compressed_source = FALSE;
- X if (stat (fullname, &stat_buf)) {
- X strcat (fullname, ".Z"); /* Check for compressed file */
- X if (stat (fullname, &stat_buf)) {
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, file %s not found in specified \
- Xarchive.\n", filename, BAD_ARCHIVE);
- X fax_it = FALSE;
- X return;
- X }
- X compressed_source = TRUE;
- X }
- X if (request [strlen (request) - 1] == '\n')
- X request [strlen (request) - 1] = EOS;
- X sprintf (subject, "%s (%d/%d)", request, i, abs (count));
- X if (!interactive) {
- X if (count < 0)
- X syscom ("%s %s | uuencode %s > %s",
- X (compressed_source ? "zcat" : "cat"), fullname, filename,
- X (uue_file = mystrdup (tmpnam (NULL)))),
- X compressed_source = FALSE,
- X strcpy (fullname, uue_file),
- X stat (fullname, &stat_buf),
- X *(filesizes + i - 1) = stat_buf.st_size;
- X slash = subject;
- X while ((slash = strchr (slash + 1, '/')) && !isspace (*(slash - 1)));
- X if (slash)
- X shadow_password (slash + 1);
- X {
- X long int offset = 0, cnt = 0, nbytes, nsubparts;
- X char _subject[MAX_LINE], _count[32], *part_copy = NULL;
- X FILE *file = NULL;
- X struct stat stat_buf;
- X
- X if (sys.options & LIMIT_FILES) {
- X if (compressed_source)
- X part_copy = mystrdup (tmpnam (NULL)),
- X syscom ("zcat %s > %s", fullname, part_copy);
- X OPEN_FILE (file, (compressed_source ? part_copy : fullname), "r",
- X "get");
- X fstat (fileno (file), &stat_buf);
- X }
- X while (offset < *(filesizes + i - 1)) {
- X strcpy (_subject, subject);
- X if (sys.options & LIMIT_FILES &&
- X *(filesizes + i - 1) > sys.limits.files)
- X /* nsubparts could be inaccurate if during the process of looking
- X for the nearest newlines not beyond the limit, the total number
- X of bytes backtracked is an integer multiple of the limit; that
- X can be very frequent if the limit is too small */
- X nsubparts = (long int)
- X ceil ((float) *(filesizes + i - 1) / (float) sys.limits.files),
- X sprintf (_subject + strlen (_subject), " [%ld/%ld]", (++cnt),
- X nsubparts),
- X sprintf (_count, " (subpart %ld/%ld)", cnt, nsubparts);
- X create_header (&f, mailforwardf, sys.server.address, sender, _subject,
- X COPY_OWNER (ccget), OK, FALSE, FALSE);
- X fprintf (f, "Archive %s, file %s.\nPart %d/%d%s, \
- Xtotal size %ld bytes:\n\n",
- X archive_orig, filename, i, abs (count), (cnt ? _count : ""),
- X *(filesizes + i - 1));
- X fprintf (f, "------------------------------ Cut here \
- X------------------------------\n");
- X fclose (f);
- X if (sys.options & LIMIT_FILES) { /* Calculate nearest newline */
- X if (*(filesizes + i - 1) > sys.limits.files) {
- X nbytes = sys.limits.files;
- X fseek (file, (offset + nbytes - 1 < stat_buf.st_size ?
- X offset + nbytes - 1 : stat_buf.st_size - 1),
- X SEEK_SET);
- X while (fgetc (file) != '\n' && nbytes > 1)
- X --nbytes,
- X fseek (file, -2L, SEEK_CUR);
- X if (nbytes == 1)
- X nbytes = sys.limits.files;
- X }
- X else
- X nbytes = *(filesizes + i - 1);
- X }
- X else
- X nbytes = *(filesizes + i - 1);
- X CAT_FILE;
- X offset += nbytes;
- X echo_append ("------------------------------ Cut here \
- X------------------------------", mailforwardf);
- X APPEND_TELNET ("get");
- X DELIVER_MAIL (sender, COPY_OWNER (ccget));
- X }
- X if (file) {
- X fclose (file);
- X if (part_copy)
- X unlink (part_copy),
- X free ((char *) part_copy);
- X }
- X }
- X }
- X else { /* Interactive */
- X if (fax_it)
- X cp (mailforwardf, ((s = mystrdup (tmpnam (NULL))))),
- X syscom ("%s < %s %s > /dev/null; rm -f %s &", sys.fax.prog, s,
- X sys.fax.fax_no, s),
- X free ((char *) s),
- X reply_code (OK);
- X else {
- X if (!strcmp (req, "GET"))
- X reply_code (WRITE_TO_FILE_ASC); /* Other modes possible */
- X else
- X reply_code (OK);
- X syscom ("%s %s >> %s", (compressed_source ? "zcat" : "cat"), fullname,
- X mailforwardf);
- X }
- X }
- X if (uue_file)
- X unlink (uue_file),
- X free ((char *) uue_file),
- X uue_file = NULL;
- X }
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
- X#endif
- X free ((long int *) filesizes);
- X fax_it = FALSE;
- X}
- X
- X/*
- X Search the specified archive for matches of the supplied extended regular
- X expression.
- X*/
- X
- Xvoid search (char *request, char *params, char *sender)
- X{
- X FILE *f, *index, *dir, *master, *fp;
- X char archive [MAX_LINE];
- X char arch [MAX_LINE];
- X char cur_archive [MAX_LINE];
- X char line [MAX_LINE];
- X char file [MAX_LINE];
- X char _line [MAX_LINE];
- X char _line_copy [MAX_LINE];
- X char fullpath [MAX_LINE];
- X char regex [MAX_LINE];
- X char fullname [MAX_LINE];
- X char desc [MAX_LINE];
- X char junk [MAX_LINE];
- X char user_password [MAX_LINE];
- X char sys_password [MAX_LINE];
- X char arch_dir [MAX_LINE];
- X char *slash, *part_copy = NULL, *quote;
- X BOOLEAN continued, compressed_source, all, header_printed, found = FALSE;
- X int count, parts, i;
- X long int filesize;
- X struct stat stat_buf;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X archive[0] = fullpath[0] = fullname[0] =
- X cur_archive[0] = RESET (regex);
- X sscanf (params, "%s %s", archive, user_password);
- X sscanf (original_params, "%s %s %s", junk, junk, regex);
- X if (archive[0] == EOS) {
- X reject_mail (sender, request, "SEARCH: missing arguments\n\n\
- XSyntax: search <archive | path-to-archive> [/password] [-all] \
- X<pattern>\n", SYNTAX_ERROR, 0);
- X fax_it = FALSE;
- X return;
- X }
- X locase (archive);
- X if (user_password[0] == '/') /* Remove leading '/' */
- X sprintf (user_password, "%s", user_password + 1);
- X else if (!strcmp (user_password, "-ALL"))
- X RESET (user_password),
- X all = TRUE,
- X sscanf (original_params, "%s %s %[^\n]", junk, junk, regex);
- X else
- X sscanf (original_params, "%s %[^\n]", junk, regex),
- X RESET (user_password);
- X if (regex[0] != EOS) {
- X part_copy = mystrdup (regex);
- X upcase (part_copy);
- X if (!strcmp (part_copy, "-ALL"))
- X all = TRUE,
- X sscanf (original_params, "%s %s %s %[^\n]", junk, junk, junk, regex);
- X else if (user_password[0] != EOS)
- X sscanf (original_params, "%s %s %[^\n]", junk, junk, regex);
- X free ((char *) part_copy);
- X part_copy = NULL;
- X }
- X else {
- X reject_mail (sender, request,
- X tsprintf ("Too few arguments to SEARCH\n\n\
- XSyntax: search <archive | path-to-archive> [/password] [-all] <pattern>\n"),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X clean_request (regex);
- X if (regex[0] == '\'') {
- X sprintf (regex, "%s", regex + 1);
- X if (regex[0] == EOS || !re_strcmp ("'[ \t]*$", regex, NULL)) {
- X reject_mail (sender, request, "Mismatched or misplaced quotes\n",
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X quote = strrchr (regex, '\'');
- X *quote = EOS;
- X }
- X else if (regex[0] == '\"') {
- X sprintf (regex, "%s", regex + 1);
- X if (regex[0] == EOS || !re_strcmp ("\"[ \t]*$", regex, NULL)) {
- X reject_mail (sender, request, "Mismatched or misplaced quotes\n",
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X quote = strrchr (regex, '"');
- X *quote = EOS;
- X }
- X if (regex[0] == EOS) {
- X reject_mail (sender, request, "Empty regular expression\n", SYNTAX_ERROR, 0);
- X return;
- X }
- X if (re_strcmp (regex, "", NULL) < 0) {
- X reject_mail (sender, request, "Malformed regular expression\n",
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X sprintf (fullpath, "%s/%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE, INDEX);
- X strcpy (cur_archive, archive);
- X if ((slash = strchr (cur_archive, '/')))
- X *slash = EOS;
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("search", SEM_ARCHIVES);
- X#endif
- X while (archive[0] != EOS) { /* Check all archives specified */
- X if ((master = fopen (fullpath, "r")) == NULL) {
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("search", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("%s: Sorry, no index found.\n", cur_archive,
- X BAD_ARCHIVE);
- X return;
- X }
- X while (!feof (master)) { /* Look at the current index for fullpath */
- X fullpath[0] = arch[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, master);
- X if (line[0] != EOS) {
- X sscanf (line, "%s %s\n", arch, fullpath);
- X locase (arch);
- X if (!strcmp (arch, cur_archive)) {
- X found = TRUE;
- X break;
- X }
- X }
- X }
- X fclose (master);
- X if (!found) {
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("search", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("%s: not a valid archive or path.\n", cur_archive,
- X SYNTAX_ERROR);
- X return;
- X }
- X if ((slash = strchr (archive, '/')))
- X sprintf (archive, "%s", slash + 1); /* Move down the path */
- X else
- X sprintf (archive, "%s", archive + strlen (cur_archive));
- X strcpy (cur_archive, archive);
- X if ((slash = strchr (cur_archive, '/')))
- X *slash = EOS;
- X if (cur_archive[0] != EOS)
- X sprintf (fullpath, "%s/%s", fullpath, INDEX);
- X }
- X sscanf (params, "%s", archive);
- X sprintf (fullname, "%s/%s", fullpath, INDEX);
- X if ((index = fopen (fullname, "r")) == NULL) { /* Open index */
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("search", SEM_ARCHIVES);
- X#endif
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, no index found in archive %s.\n", archive,
- X BAD_ARCHIVE);
- X return;
- X }
- X slash = request;
- X while ((slash = strchr (slash + 1, '/')) && !isspace (*(slash - 1)));
- X if (slash)
- X shadow_password (slash + 1);
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccindex), OK, FALSE, FALSE);
- X fprintf (f, "Matches for pattern %s ...\n", regex);
- X locase (regex);
- X count = 0;
- X while (!feof (index)) { /* Echo archive; goto archive and get DIR file */
- X fullpath[0] = archive[0] = sys_password[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, index);
- X if (line[0] != EOS) {
- X sscanf (line, "%s %s %s\n", archive, fullpath, sys_password);
- X upcase (sys_password);
- X if (!count || all) { /* Search files of the top level archive only */
- X fprintf (f, "\n%s: %s ", (!count ? "--- Archive" : "--- Subarchive"),
- X archive);
- X if (!strncmp (fullpath, ARCHIVE_DIR, strlen (ARCHIVE_DIR)))
- X fprintf (f, "(path: %s) ", fullpath + strlen (ARCHIVE_DIR) + 1);
- X fprintf (f, "\n");
- X if (sys_password[0] != EOS && strcmp (user_password, sys_password)) {
- X reply_code (RESTRICTED_REQ);
- X fprintf (f, "This archive requires special privileges for access.\n");
- X continue;
- X }
- X if (chdir (fullpath))
- X fprintf (f, "%s: Sorry, archive out of date.\n", archive);
- X else { /* Open DIR and get file names */
- X if ((dir = fopen (DIRF, "r")) == NULL)
- X reply_code (BAD_ARCHIVE),
- X fprintf (f, "Cannot obtain directory information.\n");
- X else {
- X while (!feof (dir)) {
- X line[0] = junk[0] = RESET (file);
- X fscanf (dir, "%s %d ", file, &parts);
- X if (file[0] != EOS) {
- X for (i = 0; i < abs (parts); i++)
- X fscanf (dir, "%ld ", &filesize);
- X fscanf (dir, "%s", arch_dir);
- X do { /* Get file description */
- X RESET (desc);
- X fgets (desc, MAX_LINE - 2, dir);
- X if (desc [0] != EOS && desc[strlen (desc) - 1] == '\n')
- X desc[strlen (desc) - 1] = EOS;
- X continued = FALSE;
- X if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
- X desc[strlen (desc) - 1] = EOS,
- X continued = TRUE;
- X } while (continued);
- X if (parts > 0) { /* Binaries are not searched */
- X for (i = 0; i < parts; i++) {
- X RESET (fullname);
- X if (parts > 1)
- X sprintf (fullname, "%s/%s%d", arch_dir, file, i);
- X else
- X sprintf (fullname, "%s/%s", arch_dir, file);
- X compressed_source = FALSE;
- X if (stat (fullname, &stat_buf)) {
- X strcat (fullname, ".Z"); /* Check for compressed file */
- X if (stat (fullname, &stat_buf))
- X continue; /* Error in archive */
- X compressed_source = TRUE;
- X }
- X if (compressed_source)
- X part_copy = mystrdup (tmpnam (NULL)),
- X syscom ("zcat %s > %s", fullname, part_copy);
- X OPEN_FILE (fp, (compressed_source ? part_copy :
- X fullname), "r", "search");
- X header_printed = FALSE;
- X while (!feof (fp)) {
- X RESET (_line);
- X fgets (_line, MAX_LINE - 2, fp);
- X strcpy (_line_copy, _line);
- X if (_line_copy[0] != EOS &&
- X _line_copy[strlen (_line_copy) - 1] == '\n')
- X _line_copy[strlen (_line_copy) - 1] = EOS;
- X locase (_line);
- X if (_line[0] != EOS &&
- X re_strcmp (regex, _line, NULL) > 0) {
- X if (!header_printed)
- X if (parts > 1)
- X fprintf (f, "\n>>> File %s, part %d:\n", file, i);
- X else
- X fprintf (f, "\n>>> File %s:\n", file);
- X fprintf (f, "%s\n", _line_copy);
- X header_printed = TRUE;
- X }
- X }
- X if (header_printed)
- X fprintf (f, "<<< End of matches in file %s\n", file);
- X fclose (fp);
- X if (part_copy)
- X unlink (part_copy),
- X free ((char *) part_copy),
- X part_copy = NULL;
- X }
- X }
- X }
- X }
- X fclose (dir);
- X }
- X }
- X }
- X }
- X ++count;
- X }
- X fclose (index);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("search", SEM_ARCHIVES);
- X#endif
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, COPY_OWNER (ccindex));
- X}
- X
- X/*
- X Give specific information about this release.
- X*/
- X
- Xvoid release (char *request, char *params, char *sender)
- X{
- X char param [MAX_LINE];
- X FILE *f;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
- X reject_mail (sender, request, tsprintf ("Invalid RELEASE option%s\n\
- XSyntax: release\n", params), SYNTAX_ERROR, 0);
- X return;
- X }
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X COPY_OWNER (ccrelease), OK, FALSE, FALSE);
- X fprintf (f, "ListProcessor, version %s\nRevision level: %s\n", VERSION,
- X REV_LEVEL);
- X fprintf (f, "Last update: %s\nManager: %s\nListProcessor address: %s\n",
- X UPDATE_DATE, sys.manager, sys.server.address);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, COPY_OWNER (ccrelease));
- X}
- X
- X/*
- X Forward a 'request' to all servers handling peer lists.
- X*/
- X
- Xvoid notify_peer_servers (char *file, char *request, char *params, char *sender)
- X{
- X FILE *f, *mail;
- X char *mail_method;
- X char email [MAX_LINE];
- X char mode [MAX_LINE];
- X char alias [MAX_LINE];
- X char listproc [MAX_LINE];
- X char servers [MAX_LINE];
- X char subject [MAX_LINE];
- X char *file_tmp = mystrdup (tmpnam (NULL));
- X
- X if (peer_server_request || do_not_notify_peer_server)
- X return;
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("notify_peer_servers", SEM_LISTFILES);
- X#endif
- X cp (file, file_tmp);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("notify_peer_servers", SEM_LISTFILES);
- X#endif
- X OPEN_FILE (f, file_tmp, "r", "notify_peer_servers");
- X sprintf (subject, "%s %s", PEER_SERVER_REQUEST, sys.server.address);
- X RESET (servers);
- X if (sys.options & USE_ENV_VAR) {
- X if ((mail_method = (char *) malloc ((10 + strlen (sys.mail.env_var) +
- X strlen (sender) +
- X strlen (sys.mail.mail_prog))
- X * sizeof (char))) == NULL)
- X report_progress (report, "\nnotify_peer_servers(): malloc() failed",
- X TRUE),
- X gexit (11);
- X sprintf (mail_method, "env - %s=%s %s ", sys.mail.env_var,
- X sender, sys.mail.mail_prog);
- X }
- X else {
- X if ((mail_method = (char *) malloc ((strlen (sys.mail.method) + 1)
- X * sizeof (char))) == NULL)
- X report_progress (report, "\nnotify_peer_servers(): malloc() failed",
- X TRUE),
- X gexit (11);
- X strcpy (mail_method, sys.mail.method);
- X }
- X while (!feof (f)) {
- X email[0] = mode[0] = alias[0] = RESET (listproc);
- X fscanf (f, "%s %s %s %s\n", email, mode, alias, listproc);
- X if (email[0] != EOS) { /* Send mail to peer server */
- X sprintf (servers + strlen (servers), "%s\n", listproc);
- X create_header (&mail, mailforwardf, sender, listproc,
- X subject, FALSE, OK, FALSE, FALSE);
- X fprintf (mail, "%s %s %s\n", request, alias, params);
- X COMPLETE_TELNET (mail);
- X fclose (mail);
- X if (sys.options & USE_SYSMAIL)
- X sysmail (mailforwardf);
- X else
- X syscom ("%s '%s' < %s", mail_method,
- X (((sys.options & USE_TELNET) == 0) ? locase (listproc) : " "),
- X mailforwardf);
- X }
- X }
- X if (servers[0] != EOS) { /* Notify sender as well */
- X create_header (&mail, mailforwardf, sys.server.address, sender,
- X tsprintf ("Notification from %s", sys.server.address),
- X FALSE, OK, FALSE, FALSE);
- X fprintf (mail, "%s: Your request has been forwarded to the following peer \
- Xservers,\nwho will forward you with a copy of their own results:\n\n%s",
- Xupcase (request), servers);
- X COMPLETE_TELNET (mail);
- X fclose (mail);
- X if (sys.options & USE_SYSMAIL)
- X sysmail (mailforwardf);
- X else
- X syscom ("%s %s < %s", mail_method,
- X (((sys.options & USE_TELNET) == 0) ? locase (sender) : ""),
- X mailforwardf);
- X }
- X unlink (file_tmp);
- X free ((char *) file_tmp);
- X free ((char *) mail_method);
- X fclose (f);
- X}
- X
- X/*
- X Internal request generated by catmail; the text that follows is sent
- X to 'sender'. This request is generated only for moderated lists.
- X*/
- X
- Xvoid notify (char *request, char *params, char *sender)
- X{
- X FILE *f;
- X char line [MAX_LINE];
- X
- X create_header (&f, mailforwardf, sys.server.address, sender, "Notification",
- X FALSE, OK, FALSE, FALSE);
- X RESET (line);
- X while (!feof (mail) && /* Copy till eof or next message */
- X (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE))))
- X fputs (line, f),
- X RESET (line),
- X fgets (line, MAX_LINE - 2, mail);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, FALSE);
- X if (!strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))
- X fseek (mail, -strlen (line), SEEK_CUR); /* Move back to beginning */
- X}
- X
- X/*
- X Approve a message for a moderated list. The owner has supplied message
- X a tag for a message approved, so look for it in the moderated file,
- X and append it to the mail file, then remove it from the moderated file.
- X*/
- X
- Xvoid approve (char *request, char *params, char *sender)
- X{
- X char password [MAX_LINE];
- X char req [MAX_LINE];
- X char line [MAX_LINE];
- X char prev_line [MAX_LINE];
- X char moreparams [MAX_LINE];
- X char match [MAX_LINE];
- X FILE *f, *moderated, *mail;
- X int lfd = 2, lfd2 = 2, tag, tag_to_approve = 0;
- X long int sig_mask;
- X BOOLEAN copy = FALSE;
- X
- X moreparams[0] = req[0] = RESET (password);
- X strcpy (req, request);
- X sscanf (params, "%s %d %s", password, &tag_to_approve, moreparams);
- X shadow_password (params);
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params);
- X if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
- X NOT_LIST_OWNER; /* Hacker attack */
- X return;
- X }
- X if (password[0] == EOS) {
- X reject_mail (sender, request,
- X tsprintf ("Missing password for %s request\n\n\
- XSyntax: approve <list> <password> <tag>\n", req), SYNTAX_ERROR, 0);
- X return;
- X }
- X if (strcmp (password, sys.lists[listid].password)) {
- X reject_mail (sender, request,
- X tsprintf ("Invalid password for %s request\n", req),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (tag_to_approve == 0) {
- X reject_mail (sender, request,
- X tsprintf ("Invalid or missing tag number for %s request\n\n\
- XSyntax: approve <list> <password> <tag>\n", req), SYNTAX_ERROR, 0);
- X return;
- X }
- X if (moreparams[0] != EOS) {
- X reject_mail (sender, request,
- X tsprintf ("Too many tag numbers to %s request\n\n\
- XSyntax: approve <list> <password> <tag>\n", req), SYNTAX_ERROR, 0);
- X return;
- X }
- X#ifndef NO_LOCKS
- X if ((lfd = lock_file (list_mail_f, O_RDWR | O_CREAT, 416, TRUE)) < 0)
- X switch (lfd) {
- X case CANT_OPEN:
- X CANNOT_STAT_FILE (list_mail_f, "open");
- X report_progress (report,
- X tsprintf ("\nCould not stat file %s", list_mail_f),
- X TRUE);
- X gexit (1);
- X case CANT_LOCK:
- X CANNOT_STAT_FILE (list_mail_f, "lock");
- X return;
- X }
- X if ((lfd2 = lock_file (list_moderated_f, O_RDWR | O_CREAT, 416, TRUE)) < 0)
- X switch (lfd2) {
- X case CANT_OPEN:
- X CANNOT_STAT_FILE (list_moderated_f, "open");
- X report_progress (report,
- X tsprintf ("\nCould not stat file %s", list_moderated_f),
- X TRUE);
- X gexit (1);
- X case CANT_LOCK:
- X unlock_file (lfd);
- X CANNOT_STAT_FILE (list_moderated_f, "lock");
- X return;
- X }
- X#endif
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X OPEN_FILE (moderated, list_moderated_f, "r", "approve");
- X OPEN_FILE (mail, list_mail_f, "a", "approve");
- X prev_line[0] = RESET (line);
- X while (!feof (moderated)) {
- X if (!strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)) &&
- X copy)
- X break; /* We are at the beginning of another message; stop copying */
- X strcpy (match, "\\1");
- X if (re_strcmp (MESSAGE_TAG, line, match) > 0) { /* Get tag # */
- X sprintf (line, "%s", line + strlen (match));
- X sscanf (line, "%d", &tag);
- X RESET (line); /* Blow away Message-Tag: */
- X if (tag_to_approve == tag)
- X copy = TRUE;
- X }
- X if (copy && prev_line[0] != EOS)
- X fprintf (mail, "%s", prev_line);
- X strcpy (prev_line, line);
- X RESET (line);
- X fgets (line, MAX_LINE - 2, moderated);
- X }
- X if (copy && prev_line[0] != EOS)
- X fprintf (mail, "%s", prev_line);
- X fclose (moderated);
- X fclose (mail);
- X if (!copy) { /* Message to be approved not found */
- X NO_SUCH_MESSAGE_TAG (tag_to_approve);
- X goto abort;
- X }
- X remove_msg (list_moderated_f, tag_to_approve, report);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
- X OK, FALSE, FALSE);
- X fprintf (f, "Your request was successfully completed.\n");
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, FALSE);
- X abort: ;
- X#ifndef NO_LOCKS
- X unlock_file (lfd);
- X unlock_file (lfd2);
- X#endif
- X}
- X
- X/*
- X Discard a message from a moderated list.
- X*/
- X
- Xvoid discard (char *request, char *params, char *sender)
- X{
- X char password [MAX_LINE];
- X char req [MAX_LINE];
- X char moreparams [MAX_LINE];
- X FILE *f;
- X int tag_to_discard = 0, lfd = 2;
- X long int sig_mask;
- X
- X moreparams[0] = req[0] = RESET (password);
- X strcpy (req, request);
- X sscanf (params, "%s %d %s", password, &tag_to_discard, moreparams);
- X shadow_password (params);
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params);
- X if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
- X NOT_LIST_OWNER; /* Hacker attack */
- X return;
- X }
- X if (password[0] == EOS) {
- X reject_mail (sender, request, tsprintf ("Missing password for %s request\n\n\
- XSyntax: discard <list> <password> <tag>\n", req), SYNTAX_ERROR, 0);
- X return;
- X }
- X if (strcmp (password, sys.lists[listid].password)) {
- X reject_mail (sender, request,
- X tsprintf ("Invalid password for %s request\n", req),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (tag_to_discard == 0) {
- X reject_mail (sender, request,
- X tsprintf ("Invalid or missing tag number for %s request\n\n\
- XSyntax: discard <list> <password> <tag>\n", req),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X if (moreparams[0] != EOS) {
- X reject_mail (sender, request,
- X tsprintf ("Too many tag numbers to %s request\n\n\
- XSyntax: discard <list> <password> <tag>\n", req), SYNTAX_ERROR, 0);
- X return;
- X }
- X#ifndef NO_LOCKS
- X if ((lfd = lock_file (list_moderated_f, O_RDWR | O_CREAT, 416, TRUE)) < 0)
- X switch (lfd) {
- X case CANT_OPEN:
- X CANNOT_STAT_FILE (list_moderated_f, "open");
- X report_progress (report,
- X tsprintf ("\nCould not stat file %s", list_moderated_f),
- X TRUE);
- X gexit (1);
- X case CANT_LOCK:
- X CANNOT_STAT_FILE (list_moderated_f, "lock");
- X return;
- X }
- X#endif
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X if (!remove_msg (list_moderated_f, tag_to_discard, report)) {
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X NO_SUCH_MESSAGE_TAG (tag_to_discard);
- X goto abort;
- X }
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
- X OK, FALSE, FALSE);
- X fprintf (f, "Your request was successfully completed.\n");
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, FALSE);
- X abort: ;
- X#ifndef NO_LOCKS
- X unlock_file (lfd);
- X#endif
- X}
- X
- X/*
- X Execute a program and reply with the output from stdout and stderr.
- X*/
- X
- Xvoid execute (char *request, char *params, char *sender)
- X{
- X char password [MAX_LINE];
- X char req [MAX_LINE];
- X char sstdout [MAX_LINE];
- X char sstderr [MAX_LINE];
- X char *prog = NULL;
- X FILE *f;
- X struct stat stat_buf;
- X
- X req[0] = RESET (password);
- X strcpy (req, request);
- X sscanf (params, "%s ", password);
- X shadow_password (original_params);
- X sprintf (request + strlen (request), "%s", original_params);
- X if (password[0] == EOS) {
- X reject_mail (sender, request,
- X tsprintf ("Missing password for %s request\n\n\
- XSyntax: execute <password> #<prog> [args]\n", req), SYNTAX_ERROR, 0);
- X return;
- X }
- X if (strcmp (password, sys.server.password)) {
- X reject_mail (sender, request, tsprintf ("Invalid password for %s request\n",
- X req), SYNTAX_ERROR, 0);
- X return;
- X }
- X if ((prog = strchr (original_params, '#')) == NULL) {
- X reject_mail (sender, request,
- X tsprintf ("Missing '#' for %s request\n\n\
- XSyntax: execute <password> #<prog> [args]\n", req), SYNTAX_ERROR, 0);
- X return;
- X }
- X original_params [strlen (original_params) - 1] = EOS; /* Remove \n */
- X sprintf (sstdout, "%s.%d", STDOUT, getpid());
- X sprintf (sstderr, "%s.%d", STDERR, getpid());
- X syscom ("%s > %s 2> %s", prog + 1, sstdout, sstderr);
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
- X OK, FALSE, FALSE);
- X if (!stat (sstdout, &stat_buf) && stat_buf.st_size > 0) {
- X fprintf (f, "Output from stdout:\n");
- X fclose (f);
- X cat_append (sstdout, mailforwardf);
- X APPEND_TELNET ("execute");
- X DELIVER_MAIL (sender, FALSE);
- X }
- X if (!stat (sstderr, &stat_buf) && stat_buf.st_size > 0) {
- X if (interactive) /* In case execute is ever allowed for live connections */
- X if (stat (sstdout, &stat_buf))
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X FALSE, OK, FALSE, FALSE);
- X else
- X f = fopen (mailforwardf, "a");
- X else
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X FALSE, OK, FALSE, FALSE);
- X fprintf (f, "Output from stderr:\n");
- X fclose (f);
- X cat_append (sstderr, mailforwardf);
- X APPEND_TELNET ("execute");
- X DELIVER_MAIL (sender, FALSE);
- X }
- X unlink (sstdout);
- X unlink (sstderr);
- X}
- X
- X/*
- X Execute a UNIX command allowed for the specified list by members of the list,
- X and receive the output from stdout and/or stderr.
- X*/
- X
- Xvoid unix_cmd (char *request, char *params, char *sender)
- X{
- X char password [MAX_LINE];
- X char req [MAX_LINE];
- X char sstdout [MAX_LINE];
- X char sstderr [MAX_LINE];
- X char prog [10240], *_prog, *args [10], *blank;
- X FILE *f;
- X struct stat stat_buf;
- X _CMDS *unix_cmd = sys.lists[listid].unix_cmds;
- X int nargs;
- X long int sig_mask;
- X
- X if (matched_rlists) { /* Request for a remote list; notify sender */
- X NOTIFY_OF_REQUEST_FORWARDING;
- X FORWARD_REQUEST;
- X return;
- X }
- X req[0] = RESET (password);
- X strcpy (req, request);
- X sscanf (params, "%s ", password);
- X _prog = original_params;
- X while (*_prog != EOS && isspace (*_prog)) /* Skip over list */
- X ++_prog;
- X while (*_prog != EOS && !isspace (*_prog)) /* Get to password */
- X ++_prog;
- X shadow_password (_prog);
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X _prog);
- X if (subscribed (report, sender, subscribersf, NULL, NULL,
- X aliasesf, TRUE) == NOTSUBSCRIBED) {
- X MEMBERS_ONLY;
- X return;
- X }
- X if (password[0] == EOS) {
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
- X OK, FALSE, FALSE);
- X fprintf (f, "You may run the following commands:\n\n");
- X while (unix_cmd)
- X fprintf (f, "%s (%s)\n", unix_cmd->name, unix_cmd->comment),
- X unix_cmd = unix_cmd->next;
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender, FALSE);
- X return;
- X }
- X if (!sys.lists[listid].unix_cmds) {
- X reject_mail (sender, request, tsprintf ("No commands to execute for %s \
- Xrequest\n", req), SYNTAX_ERROR, 0);
- X return;
- X }
- X if ((blank = strchr (original_params, '`')) ||
- X (blank = strchr (original_params, '|')) ||
- X (blank = strchr (original_params, '<')) ||
- X (blank = strchr (original_params, '>')) ||
- X (blank = strchr (original_params, ':'))) {
- X reject_mail (sender, request,
- X tsprintf ("Invalid character %c in request.\n", *blank),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X clean_request (_prog); /* Skip leading blanks */
- X while (*_prog != EOS && *_prog == 'X') ++_prog;
- X clean_request (_prog); /* Skip leading blanks */
- X if (*_prog == EOS) {
- X reject_mail (sender, request, tsprintf ("Missing command to run for %s \
- Xrequest\n\n\
- XSyntax: run <list> [<password> <cmd> [args]]\n", req), SYNTAX_ERROR, 0);
- X return;
- X }
- X memset ((char *) prog, EOS, 10240);
- X sscanf (_prog, "%s ", prog);
- X upcase (prog);
- X while (unix_cmd) {
- X if (!strcmp (unix_cmd->name, prog)) {
- X if (strcmp (password, unix_cmd->password)) {
- X reject_mail (sender, request, tsprintf ("Invalid password for %s request\n",
- X req), SYNTAX_ERROR, 0);
- X return;
- X }
- X strcpy (prog, unix_cmd->cmd);
- X break;
- X }
- X unix_cmd = unix_cmd->next;
- X }
- X if (!unix_cmd) {
- X reject_mail (sender, request, tsprintf ("Unknown command %s\n", prog),
- X SYNTAX_ERROR, 0);
- X return;
- X }
- X original_params [strlen (original_params) - 1] = EOS; /* Remove \n */
- X while (*_prog != EOS && isspace (*_prog)) /* Skip over cmd */
- X ++_prog;
- X while (*_prog != EOS && !isspace (*_prog)) /* Get to arguments */
- X ++_prog;
- X while (*_prog != EOS && isspace (*_prog))
- X ++_prog;
- X nargs = 0;
- X while (*_prog != EOS && nargs < 9) {
- X if (!(args[nargs] = (char *) malloc ((strlen (_prog) + 1) * sizeof (char))))
- X report_progress (report, "\nunix_cmd(): malloc() failed", TRUE),
- X gexit (11);
- X strcpy (args[nargs], _prog);
- X if ((blank = strchr (args[nargs], ' ')) ||
- X (blank = strchr (args[nargs], '\t')))
- X *blank = EOS;
- X ++nargs;
- X while (*_prog != EOS && !isspace (*_prog))
- X ++_prog;
- X while (*_prog != EOS && isspace (*_prog)) /* Get to next arg */
- X ++_prog;
- X }
- X _prog = prog;
- X while (*_prog != EOS && (_prog = strchr (_prog, '$')))
- X if (*(_prog + 1) == '*') /* Insert all user arguments */
- X _prog += insert_word (_prog, args, nargs, 0, 2);
- X else if (isdigit (*(_prog + 1)) && *(_prog + 1) > '0')
- X _prog += insert_word (_prog, args, 1, (int) *(_prog + 1) - '0' - 1, 2);
- X else
- X ++_prog;
- X while (nargs)
- X free ((char *) args[--nargs]);
- X#ifdef bsd
- X sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
- X#elif defined (svr4) || defined (svr3)
- X sighold (SIGINT);
- X sighold (SIGTERM);
- X#endif
- X sprintf (sstdout, "%s.%d", STDOUT, getpid());
- X sprintf (sstderr, "%s.%d", STDERR, getpid());
- X syscom ("%s > %s 2> %s", prog, sstdout, sstderr);
- X#ifdef bsd
- X sigsetmask (sig_mask);
- X#elif defined (svr4) || defined (svr3)
- X sigrelse (SIGINT);
- X sigrelse (SIGTERM);
- X#endif
- X create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
- X OK, FALSE, FALSE);
- X if (!stat (sstdout, &stat_buf) && stat_buf.st_size > 0) {
- X fprintf (f, "Output from stdout:\n");
- X fclose (f);
- X cat_append (sstdout, mailforwardf);
- X APPEND_TELNET ("execute");
- X DELIVER_MAIL (sender, FALSE);
- X }
- X if (!stat (sstderr, &stat_buf) && stat_buf.st_size > 0) {
- X if (interactive)
- X if (stat (sstdout, &stat_buf))
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X FALSE, OK, FALSE, FALSE);
- X else
- X f = fopen (mailforwardf, "a");
- X else
- X create_header (&f, mailforwardf, sys.server.address, sender, request,
- X FALSE, OK, FALSE, FALSE);
- X fprintf (f, "Output from stderr:\n");
- X fclose (f);
- X cat_append (sstderr, mailforwardf);
- X APPEND_TELNET ("execute");
- X DELIVER_MAIL (sender, FALSE);
- X }
- X unlink (sstdout);
- X unlink (sstderr);
- X}
- X
- X/*
- X Initialize the commands[].
- X*/
- X
- Xvoid init_commands ()
- X{
- X COMMAND (0, "HELP", 0x1, help);
- X COMMAND (1, "SET", 0x2, set);
- X COMMAND (2, "SUBSCRIBE", 0x4, subscribe);
- X COMMAND (3, "UNSUBSCRIBE", 0x8, unsubscribe);
- X COMMAND (4, "SIGNOFF", 0x8, unsubscribe);
- X COMMAND (5, "RECIPIENTS", 0x10, recipients);
- X COMMAND (6, "REVIEW", 0x10, recipients);
- X COMMAND (7, "INFORMATION", 0x20, info);
- X COMMAND (8, "STATISTICS", 0x40, stats);
- X COMMAND (9, "SHUTDOWN", 0x80, Shutdown);
- X COMMAND (10, "RESTART", 0x100, restart);
- X COMMAND (11, "LISTS", 0x200, lists);
- X COMMAND (12, "INDEX", 0x400, Index);
- X COMMAND (13, "GET", 0x800, get);
- X COMMAND (14, "RELEASE", 0x1000, release);
- X COMMAND (15, "WHICH", 0x2000, which);
- X COMMAND (16, "SYSTEM", 0x4000, System);
- X COMMAND (17, "REPORTS", 0x8000, get_sys_files);
- X COMMAND (18, "EDIT", 0x10000, get_sys_files);
- X COMMAND (19, "PUT", 0x20000, put);
- X COMMAND (20, "NOTIFY", 0x40000, notify);
- X COMMAND (21, "APPROVE", 0x80000, approve);
- X COMMAND (22, "DISCARD", 0x100000, discard);
- X COMMAND (23, "EXECUTE", 0x200000, execute);
- X COMMAND (24, "RUN", 0x400000, unix_cmd);
- X COMMAND (25, "FAX", 0x800000, get);
- X COMMAND (26, "SEARCH", 0x1000000, search);
- X COMMAND (27, "VIEW", 0x800, get);
- X}
- X
- Xvoid usage ()
- X{
- X fprintf (stderr, "Usage: listproc [-1] [-e] [-i] [-n] [-a <LIST_ALIAS>] \
- X[-c <LIST_ALIAS>] {[-r <request>]}* {[-d <request>]}* {[-b <request>]}* [-B] \
- X[-D]\n\
- X-1: Execute only once.\n\
- X-e: Echo reports to the screen.\n\
- X-i: Interactive mode (do not send mail).\n\
- X-n: Do not notify peer servers.\n\
- X-a: Turn off automatic subscription for the specified list.\n\
- X-c: Conceal the specified list from LISTS requests.\n\
- X-r: Set restriction on 'request'.\n\
- X-d: Disable 'request'.\n\
- X-b: Batch 'request'.\n\
- X-B: Process the batch queue.\n\
- X-D: Turn debug on.\n");
- X exit (3);
- X}
- X
- Xvoid server_config (char *alias)
- X{
- X setup_string (list_mail_f, alias, LIST_MAIL_FILE);
- X setup_string (list_moderated_f, alias, LIST_MODERATED_F);
- X setup_string (infof, alias, INFO_FILE);
- X setup_string (recipf, alias, RECIP_FILE);
- X setup_string (welcomef, alias, WELCOME_FILE);
- X setup_string (subscribersf, alias, SUBSCRIBERS);
- X setup_string (aliasesf, alias, ALIASES);
- X setup_string (newsf, alias, NEWSF);
- X setup_string (peersf, alias, PEERS);
- X setup_string (headersf, alias, HEADERS);
- X setup_string (ignoredf, alias, IGNORED);
- X setup_string (aliases_timestampf, alias, ALIASES_TIMESTAMPF);
- X setup_string (ignored_timestampf, alias, IGNORED_TIMESTAMPF);
- X setup_string (info_timestampf, alias, INFO_TIMESTAMPF);
- X setup_string (subscribers_timestampf, alias, SUBSCRIBERS_TIMESTAMPF);
- X setup_string (welcome_timestampf, alias, WELCOME_TIMESTAMPF);
- X setup_string (news_timestampf, alias, NEWS_TIMESTAMPF);
- X setup_string (peers_timestampf, alias, PEERS_TIMESTAMPF);
- X}
- X
- X/*
- X Graceful exit. Remove pid file.
- X*/
- X
- Xint gexit (int exitcode)
- X{
- X unlink (tsprintf ("%s.%d", PID_SERVER, getpid()));
- X exit (exitcode);
- X}
- *-*-END-of-src/listproc.c-*-*
- echo x - src/misc.c
- sed 's/^X//' >src/misc.c <<'*-*-END-of-src/misc.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | GENERAL PURPOSE FUNCTIONS |
- X | |
- X | Version 3.0 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X*/
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#ifdef SYSLOG
- X# ifdef ultrix
- X# include <sys/syslog.h>
- X# else
- X# include <syslog.h>
- X# endif
- X#endif
- X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
- X && !defined (sequent) && !defined (unknown_port)
- X# include <malloc.h>
- X#endif
- X#include <time.h>
- X#include <string.h>
- X#include <signal.h>
- X#include <ctype.h>
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <sys/stat.h>
- X#include <fcntl.h>
- X#include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X#include <signal.h>
- X#include <math.h>
- X#include "defs.h"
- X#include "struct.h"
- X#ifdef GO_INTERACTIVE
- X# include <sys/socket.h>
- X#endif
- X
- X#define MYWEXITSTATUS(stat) ((int)(((stat)>>8)&0377))
- X
- Xextern COMMANDS commands[MAX_COMMANDS];
- Xextern REMOTE *rlists, *matched_rlists;
- Xextern BOOLEAN extract_sender (char *);
- Xextern char *options [MAX_SET_OPTIONS];
- Xextern char *values [MAX_SET_OPTIONS];
- X
- X#if !defined (__NeXT__) && !defined (__osf__) && !defined (_AIX)
- Xextern long int atoi (char *);
- X#else
- Xextern int atoi (const char *);
- X#endif
- Xextern BOOLEAN subscribed (FILE *, char *, char *, char *, char *, char *,
- X BOOLEAN);
- Xextern void process_message (char *, char *, BOOLEAN, BOOLEAN);
- Xextern int re_strcmp (char *, char *, char *);
- Xextern int mv (char *, char *);
- X
- X#ifdef __STDC__
- X# include "ansi/misc.h"
- X# include <stdarg.h>
- Xint syscom (char *, ...);
- Xextern char *tsprintf (char *, ...);
- X#else
- X# include "nonansi/misc.h"
- X# include <varargs.h>
- Xint syscom ();
- Xextern char *tsprintf ();
- X#endif
- Xint sys_config (FILE *, SYS *);
- Xvoid config_owner_prefs (SYS *, int, FILE *);
- Xchar *locase (char *);
- Xchar *upcase (char *);
- Xvoid shadow_password (char *);
- Xvoid report_progress (FILE *, char *, int);
- Xvoid distribute (FILE *, void (*)(char *, char *, BOOLEAN, BOOLEAN), FILE *,
- X char *, char *, char *, char *, BOOLEAN);
- XBOOLEAN strinstr (char *, char *);
- Xchar *extract_filename (char *);
- Xint _getopt (int, char **, char *);
- Xchar *clean_name (char *);
- Xvoid clean_request (char *);
- Xvoid get_list_name (char *, char *);
- Xvoid free_remote_matched (REMOTE **);
- Xint get_list_id (char *, SYS *, int);
- XREMOTE *check_remote (REMOTE *, char *);
- Xvoid setup_string (char *, char *, char *);
- Xchar *_strstr (char *, char *);
- Xvoid shrink (char *);
- XBOOLEAN requested_part (char *, int);
- Xvoid free_remote (REMOTE **);
- Xint my_system (char *);
- XBOOLEAN remove_msg (char *, int, FILE *);
- Xvoid read_params (char *, char *, char *, FILE *, FILE *);
- Xint lock_file (char *, int, int, BOOLEAN);
- Xvoid unlock_file (int);
- Xlong int write_to_fd (int, char *, long int);
- XBOOLEAN mkdir1 (char *, char *, char *);
- Xint otoi (char *);
- XBOOLEAN get_field (char **, char, char *);
- XBOOLEAN make_indexes (char *, char *, char *, char *, char *);
- Xint insert_word (char *, char **, int, int, int);
- Xchar *skip_to_word (char *, int);
- Xchar *mystrdup (char *);
- X
- X/*
- X Execute a system request.
- X*/
- X
- X#ifdef __STDC__
- Xint syscom (char *control, ...)
- X#else
- Xint syscom (control, va_alist)
- Xchar *control;
- Xva_dcl
- X#endif
- X{
- X char command [10240], *ambersand;
- X int mask;
- X extern SYS sys;
- X extern BOOLEAN tty_echo;
- X va_list ap;
- X int status;
- X FILE *f;
- X#ifdef ultrix
- X time_t time_is = 0;
- X#else
- X long int time_is = 0;
- X#endif
- X struct tm *t;
- X
- X#ifdef __STDC__
- X va_start (ap, control);
- X#else
- X va_start (ap);
- X#endif
- X RESET (command);
- X vsprintf (command, control, ap);
- X va_end (ap);
- X if (!_strstr (command, " 2>")) {
- X sprintf (command + strlen (command), " 2>> %s", WARNING);
- X if ((ambersand = _strstr (command, " &")))
- X *(ambersand + 1) = ' ',
- X strcat (command, " &");
- X }
- X#ifdef GO_INTERACTIVE
- X# if defined (bsd)
- X# ifdef SIGCLD
- X mask = sigblock (sigmask (SIGCLD));
- X# elif defined (SIGCHLD)
- X mask = sigblock (sigmask (SIGCHLD));
- X# endif
- X# elif (defined (svr4) || defined (svr3)) && !defined (stellar) && \
- X !defined (M_UNIX) && !defined (M_XENIX) && !defined (sco) && \
- X !defined (unknown_port)
- X# ifdef SIGCLD
- X sighold (SIGCLD);
- X# elif defined (SIGCHLD)
- X sighold (SIGCHLD);
- X# endif
- X# endif
- X#endif
- X if ((sys.options & USE_MY_SYSTEM) == 0)
- X status = system (command);
- X else
- X status = my_system (command);
- X#ifdef GO_INTERACTIVE
- X# if defined (bsd) && (defined (SIGCLD) || defined (SIGCHLD))
- X sigsetmask (mask);
- X# elif (defined (svr3) || defined (svr4)) && !defined (stellar) && \
- X !defined (M_UNIX) && !defined (M_XENIX) && !defined (sco) && \
- X !defined (unknown_port)
- X# ifdef SIGCLD
- X sigrelse (SIGCLD);
- X# elif defined (SIGCHLD)
- X sigrelse (SIGCHLD);
- X# endif
- X# endif
- X#endif
- X if (status > 0) {
- X if ((f = fopen (WARNING, "a")) != NULL)
- X fprintf (f, "\nWARNING: System call exit status %d: %s\n",
- X MYWEXITSTATUS (status), command),
- X time (&time_is),
- X t = localtime (&time_is),
- X fprintf (f, "Time/Date: %2d:%.2d:%.2d, %2d/%.2d/%2d\n",
- X t->tm_hour, t->tm_min, t->tm_sec, t->tm_mon + 1, t->tm_mday,
- X t->tm_year),
- X fclose (f);
- X if (tty_echo)
- X printf ("\nWARNING: System call exit status %d: %s\n",
- X MYWEXITSTATUS (status), command);
- X }
- X return status;
- X}
- X
- X/*
- X Initialize the 'sys' structure from the CONFIG file. It returns the number
- X of lists in the system.
- X*/
- X
- Xint sys_config (FILE *report, SYS *sys)
- X{
- X FILE *config;
- X char cmd [MAX_LINE];
- X char args [MAX_LINE];
- X char arg [MAX_LINE];
- X char line [MAX_LINE];
- X char *comment, *cmdarg, *start, *end;
- X int nlists = 0, i, j, k, id;
- X BOOLEAN notok, found;
- X REMOTE *remote;
- X PRECIOUS_HEADER *header;
- X _CMDS *unix_cmd;
- X
- X for (i = 0; i < MAX_LISTS; i++)
- X sys->lists[i].digest_lines = 1000,
- X sys->lists[i].digest_hours = 24,
- X sys->lists[i].disabled_commands = 0,
- X sys->lists[i].owner_prefs = 0,
- X sys->lists[i].header = NULL,
- X sys->lists[i].unix_cmds = NULL,
- X sys->lists[i].options = 0,
- X sys->lists[i].max_messages = 0,
- X RESET (sys->lists[i].alias),
- X RESET (sys->lists[i].address),
- X RESET (sys->lists[i].password),
- X RESET (sys->lists[i].owner),
- X RESET (sys->lists[i].comment),
- X RESET (sys->lists[i].cmdoptions),
- X RESET (sys->lists[i].arch_dir),
- X RESET (sys->lists[i].farch_dir),
- X RESET (sys->lists[i].arch_pass),
- X RESET (sys->lists[i].arch_spec);
- X RESET (sys->server.address), RESET (sys->server.cmdoptions),
- X RESET (sys->server.comment), RESET (sys->serverd_cmdoptions),
- X RESET (sys->server.password), RESET (sys->arg), RESET (sys->manager),
- X RESET (sys->organization), RESET (sys->fax.prog);
- X sys->limits.msg = sys->limits.files = 100000;
- X sys->server.manager_prefs = 0;
- X strcpy (sys->server.address, DEFAULT_SERVER_ADDRESS);
- X strcpy (sys->server.cmdoptions, DEFAULT_SERVER_CMDOPTIONS);
- X strcpy (sys->server.comment, DEFAULT_SERVER_COMMENT);
- X strcpy (sys->manager, DEFAULT_MANAGER);
- X sys->mail.method = BINMAIL;
- X strcpy (sys->mail.precedence, DEFAULT_PRECEDENCE);
- X sys->options = 0;
- X sys->users = 100;
- X sys->frequency = 5;
- X sys->batch.start = 8; /* 8 am */
- X sys->batch.stop = 20; /* 8 pm */
- X OPEN_FILE (config, CONFIG, "r", "sys_config");
- X chmod (CONFIG, 384);
- X while (! feof (config)) {
- X line [0] = args [0] = RESET (cmd);
- X fgets (line, MAX_LINE - 2, config);
- X sscanf (line, "%s", cmd);
- X if (cmd[0] == EOS)
- X continue;
- X/* fgets (args, MAX_LINE - 2, config);*/
- X read_params (line, args, cmd, config, NULL);
- X if (args [strlen (args) - 1] == '\n')
- X args [strlen (args) - 1] = EOS;
- X if (cmd[0] == '#')
- X continue;
- X if (!strcmp (locase (cmd), "list")) {
- X if (nlists >= MAX_LISTS) {
- X report_progress (report,
- X tsprintf ("\nsys_config(): List %s ignored: too many \
- Xlists\n",
- X args), FALSE);
- X continue;
- X }
- X comment = strchr (args, '#');
- X if (comment)
- X *comment = EOS;
- X sscanf (args, "%s %s %s %s", sys->lists [nlists].alias,
- X sys->lists [nlists].address, sys->lists [nlists].owner,
- X sys->lists [nlists].password);
- X if (get_list_id (sys->lists [nlists].alias, sys, nlists) >= 0 &&
- X nlists > 0)
- X report_progress (report,
- X tsprintf ("\nsys_config(): Duplicate list %s in %s",
- X sys->lists [nlists].alias, CONFIG), TRUE),
- X exit (4);
- X cmdarg = _strstr (args, " -");
- X if (!cmdarg)
- X cmdarg = _strstr (args, "\t-");
- X if (cmdarg)
- X strcat (sys->lists [nlists].cmdoptions, cmdarg);
- X upcase (sys->lists [nlists].alias);
- X locase (sys->lists [nlists].address);
- X locase (sys->lists [nlists].owner);
- X upcase (sys->lists [nlists].password);
- X ++nlists;
- X }
- X else if (!strcmp (cmd, "server")) {
- X comment = strchr (args, '#');
- X if (comment)
- X *comment = EOS;
- X sscanf (args, "%s", sys->server.address);
- X cmdarg = _strstr (args, " -");
- X if (!cmdarg)
- X cmdarg = _strstr (args, "\t-");
- X if (cmdarg)
- X strcat (sys->server.cmdoptions, cmdarg);
- X locase (sys->server.address);
- X }
- X else if (!strcmp (cmd, "remote")) {
- X if ((remote = (REMOTE *) malloc (sizeof (*remote))) == NULL)
- X report_progress (report,
- X tsprintf ("\nsys_config(): malloc() failed during \
- X'remote' in %s",
- X CONFIG), TRUE),
- X exit (11);
- X RESET (remote->inet_addr);
- X remote->port = 0;
- X sscanf (args, "%s %s %s %s %d", remote->alias, remote->address,
- X remote->listproc, remote->inet_addr, &remote->port);
- X upcase (remote->alias);
- X locase (remote->address);
- X locase (remote->listproc);
- X if (remote->inet_addr[0] == '#')
- X RESET (remote->inet_addr);
- X else if (remote->port == 0)
- X remote->port = DEFAULT_ILP_PORT;
- X comment = strchr (args, '#');
- X if (!comment)
- X report_progress (report,
- X tsprintf ("\nsys_config(): Missing # for 'remote' in %s",
- X CONFIG), TRUE),
- X exit (4);
- X RESET (remote->comment);
- X strcat (remote->comment, comment + 1);
- X remote->next = rlists; /* Link it to the existing list */
- X rlists = remote;
- X }
- X else if (!strcmp (cmd, "frequency")) {
- X sscanf (args, "%d", &sys->frequency);
- X if (sys->frequency < 0 || sys->frequency > 86400)
- X report_progress (report,
- X tsprintf ("\nsys_config(): Invalid 'frequency' \
- Xargument %d in %s",
- X sys->frequency, CONFIG), TRUE),
- X exit (4);
- X }
- X else if (!strcmp (cmd, "limit")) {
- X sscanf (args, "%s", sys->arg);
- X if (!strcmp (locase (sys->arg), "message"))
- X sys->options |= LIMIT_MSG,
- X sscanf (args, "%s %ld", sys->arg, &sys->limits.msg);
- X else if (!strcmp (sys->arg, "files"))
- X sys->options |= LIMIT_FILES,
- X sscanf (args, "%s %ld", sys->arg, &sys->limits.files);
- X else
- X report_progress (report,
- X tsprintf ("\nsys_config(): Invalid argument %s to \
- X'limit' in %s",
- X sys->arg, CONFIG), TRUE),
- X exit (4);
- X }
- X else if (!strcmp (cmd, "ceiling")) {
- X sscanf (args, "%s ", sys->arg);
- X upcase (sys->arg);
- X id = get_list_id (sys->arg, sys, nlists);
- X if (id < 0)
- X report_progress (report,
- X tsprintf ("\nsys_config(): Unrecognized list name %s \
- Xfor 'ceiling' in %s", sys->arg, CONFIG), TRUE),
- X exit (4);
- X sscanf (args, "%s %d", sys->arg, &sys->lists[id].max_messages);
- X }
- X else if (!strcmp (cmd, "batch")) {
- X sscanf (args, "%u %u", &sys->batch.start, &sys->batch.stop);
- X sys->batch.start %= 24;
- X sys->batch.stop %= 24;
- X if (sys->batch.stop == 0)
- X sys->batch.stop = 24;
- X if (sys->batch.start >= sys->batch.stop ||
- X (sys->batch.start == 0 && sys->batch.stop == 24))
- X report_progress (report, tsprintf ("\nsys_config(): Invalid times to \
- X'batch' in %s",
- X CONFIG), TRUE),
- X exit (4);
- X }
- X else if (!strcmp (cmd, "option")) {
- X sscanf (args, "%s", sys->arg);
- X if (!strcmp (locase (sys->arg), "bsd_ps"))
- X sys->options |= BSD_PS;
- X else if (!strcmp (sys->arg, "sysv_ps"))
- X sys->options |= SYSV_PS;
- X else if (!strcmp (sys->arg, "bsd_mail"))
- X sys->options |= BSD_MAIL;
- X else if (!strcmp (sys->arg, "bad_telnet"))
- X sys->options |= USE_MY_SYSTEM;
- X else if (!strcmp (sys->arg, "post_mail"))
- X sys->options |= POST_MAIL;
- X else if (!strcmp (sys->arg, "gate_mail"))
- X sys->options |= GATE_MAIL;
- X else if (!strcmp (sys->arg, "ignore_invalid_requests"))
- X sys->options |= IGNR_INVLD_RQSTS;
- X else if (!strcmp (sys->arg, "relaxed_syntax"))
- X sys->options |= RELAXED_SYNTAX;
- X else
- X report_progress (report, tsprintf ("\nsys_config(): Invalid argument \
- X%s to 'option' in %s",
- X sys->arg, CONFIG), TRUE),
- X exit (4);
- X }
- X else if (!strcmp (cmd, "serverd")) {
- X comment = strchr (args, '#');
- X if (comment)
- X *comment = EOS;
- X cmdarg = strchr (args, '-');
- X if (cmdarg)
- X strcat (sys->serverd_cmdoptions, cmdarg);
- X }
- X else if (!strcmp (cmd, "organization")) {
- X comment = strchr (args, '#');
- X if (comment)
- X *comment = EOS;
- X strcpy (sys->organization, args + 1);
- X }
- X else if (!strcmp (cmd, "restriction"))
- X sscanf (args, "%d", &sys->users);
- X else if (!strcmp (cmd, "manager"))
- X sscanf (args, "%s", sys->manager);
- X else if (!strcmp (cmd, "password"))
- X sscanf (args, "%s", sys->server.password),
- X upcase (sys->server.password);
- X else if (!strcmp (cmd, "disable")) {
- X if (commands[0].name == NULL) /* Array not initialized */
- X continue;
- X sscanf (args, "%s", sys->arg);
- X upcase (sys->arg);
- X id = get_list_id (sys->arg, sys, nlists);
- X if (id < 0)
- X report_progress (report, tsprintf ("\nsys_config(): Unrecognized \
- Xlist name %s for 'disable' in %s", sys->arg, CONFIG), TRUE),
- X exit (4);
- X sscanf (args, "%s %s", sys->arg, sys->arg); /* Get request to disable */
- X upcase (sys->arg);
- X notok = FALSE;
- X k = 0;
- X for (i = 0; i < MAX_COMMANDS; ++i) {
- X notok &= (((j = strncmp (sys->arg, commands[i].name, strlen (sys->arg)))
- X != 0) ? 1 : 0);
- X if (!j)
- X ++k,
- X sys->lists[id].disabled_commands |= commands[i].mask;
- X }
- X if (notok)
- X report_progress (report,
- X tsprintf ("\nsys_config(): Unrecognized \
- Xrequest %s to 'disable' for list %s in %s",
- X sys->arg, sys->lists[id].alias, CONFIG),
- X TRUE),
- X exit (4);
- X if (k > 1)
- X report_progress (report, tsprintf ("\nsys_config(): Ambiguous request \
- X%s to 'disable' for list %s in %s", sys->arg, sys->lists[id].alias, CONFIG),
- X TRUE),
- X exit (4);
- X }
- X else if (!strcmp (cmd, "comment")) {
- X sscanf (args, "%s", sys->arg);
- X if (!strcmp (locase (sys->arg), "server")) {
- X comment = strchr (args, '#');
- X if (!comment)
- X report_progress (report, tsprintf ("\nsys_config(): Missing # for \
- X'comment' in %s",
- X CONFIG), TRUE),
- X exit (4);
- X RESET (sys->server.comment);
- X strcat (sys->server.comment, comment + 1);
- X }
- X else { /* Some list name was specified */
- X upcase (sys->arg);
- X id = get_list_id (sys->arg, sys, nlists);
- X if (id < 0)
- X report_progress (report, tsprintf ("\nsys_config(): Unrecognized \
- Xlist name %s for 'comment' in %s", sys->arg, CONFIG), TRUE),
- X exit (4);
- X comment = strchr (args, '#');
- X if (!comment)
- X report_progress (report, tsprintf ("\nsys_config(): Missing # for \
- Xcomment in %s", CONFIG), TRUE),
- X exit (4);
- X RESET (sys->lists[id].comment);
- X strcat (sys->lists[id].comment, comment + 1);
- X }
- X }
- X else if (!strcmp (cmd, "mailmethod")) {
- X sscanf (args, "%s", sys->arg);
- X if (!strcmp (locase (sys->arg), "telnet"))
- X sys->mail.method = TELNET,
- X sys->options |= USE_TELNET;
- X else if (!strcmp (locase (sys->arg), "system")) {
- X#ifndef TCP_IP
- X report_progress (report, "\nsys_config(): No system support for \
- X'system' mailmethod. Select another method.", TRUE);
- X exit (1);
- X#endif
- X sys->options |= (USE_TELNET | USE_SYSMAIL);
- X }
- X else if (!strcmp (sys->arg, "sendmail") || !strcmp (sys->arg, "rmail")) {
- X if (!(sys->mail.method = (char *) malloc (256 * sizeof (char))))
- X report_progress (report, tsprintf ("\nsys_config(): malloc() failed \
- Xduring 'mailmethod' in %s", CONFIG), TRUE),
- X exit (11);
- X sscanf (args, "%s %s", sys->arg, sys->mail.method);
- X locase (sys->mail.method);
- X strcat (sys->mail.method, " > /dev/null 2>&1");
- X }
- X else if (!strcmp (sys->arg, "binmail"))
- X sys->mail.method = BINMAIL;
- X else if (!strcmp (sys->arg, "env_var"))
- X sys->options |= USE_ENV_VAR,
- X sscanf (args, "%s %s %s", sys->arg, sys->mail.env_var,
- X sys->mail.mail_prog),
- X locase (sys->mail.mail_prog),
- X upcase (sys->mail.env_var);
- X else
- X report_progress (report, tsprintf ("\nsys_config(): Unrecognized mail \
- Xmethod %s in %s",
- X sys->arg, CONFIG), TRUE),
- X exit (4);
- X }
- X else if (!strcmp (cmd, "digest")) { /* "digest list lines hours" */
- X sscanf (args, "%s ", sys->arg);
- X upcase (sys->arg);
- X id = get_list_id (sys->arg, sys, nlists);
- X if (id < 0)
- X report_progress (report, tsprintf ("\nsys_config(): Unrecognized list \
- Xname %s for 'digest' in %s", sys->arg, CONFIG), TRUE),
- X exit (4);
- X sscanf (args, "%s %d %d", sys->arg, &sys->lists[id].digest_lines,
- X &sys->lists[id].digest_hours);
- X }
- X else if (!strcmp (cmd, "header")) { /* Precious header lines to be saved */
- X sscanf (args, "%s ", sys->arg);
- X upcase (sys->arg);
- X id = get_list_id (sys->arg, sys, nlists);
- X if (id < 0)
- X report_progress (report, tsprintf ("\nsys_config(): Unrecognized list \
- Xname %s for 'header' in %s", sys->arg, CONFIG), TRUE),
- X exit (4);
- X if (!(comment = strchr (args, '{')))
- X report_progress (report, tsprintf ("\nsys_config(): Missing '{' for \
- X'header' in %s",
- X CONFIG), TRUE),
- X exit (4);
- X RESET (sys->arg);
- X sys->lists[id].header = NULL;
- X while (!feof (config) && strcmp (sys->arg, "}")) {
- X RESET (sys->arg);
- X fscanf (config, "%s\n", sys->arg);
- X if (sys->arg[0] == '#') {
- X fgets (sys->arg, MAX_LINE - 2, config);
- X continue;
- X }
- X if (sys->arg[0] != EOS && strcmp (sys->arg, "}")) {
- X if (! (header =
- X (PRECIOUS_HEADER *) malloc (sizeof (PRECIOUS_HEADER))))
- X report_progress (report, tsprintf ("\nsys_config(): malloc() \
- Xfailed during 'header' in %s", CONFIG), TRUE),
- X exit (11);
- X if (! (header->line =
- X (char *) malloc ((strlen (sys->arg) + 1) * sizeof (char))))
- X report_progress (report, tsprintf ("\nsys_config(): malloc() \
- Xfailed during 'header' in %s", CONFIG), TRUE),
- X exit (11);
- X strcpy (header->line, sys->arg);
- X header->next = sys->lists[id].header;
- X sys->lists[id].header = header;
- X }
- X }
- X if (feof (config) && strcmp (sys->arg, "}"))
- X report_progress (report, tsprintf ("\nsys_config(): Missing '}' for \
- X'header' for list %s in %s", sys->lists[id].alias, CONFIG), TRUE),
- X exit (4);
- X }
- X else if (!strcmp (cmd, "default")) { /* Default list values */
- X sscanf (args, "%s ", sys->arg);
- X upcase (sys->arg);
- X id = get_list_id (sys->arg, sys, nlists);
- X if (id < 0)
- X report_progress (report, tsprintf ("\nsys_config(): Unrecognized list \
- Xname %s for 'default' in %s", sys->arg, CONFIG), TRUE),
- X exit (4);
- X if (!(comment = strchr (args, '{')))
- X report_progress (report, tsprintf ("\nsys_config(): Missing '{' for \
- X'default' in %s",
- X CONFIG), TRUE),
- X exit (4);
- X RESET (sys->arg);
- X while (!feof (config) && strcmp (sys->arg, "}")) {
- X RESET (sys->arg);
- X fscanf (config, "%s ", sys->arg);
- X upcase (sys->arg);
- X if (sys->arg[0] == '#') {
- X fgets (sys->arg, MAX_LINE - 2, config);
- X continue;
- X }
- X if (sys->arg[0] != EOS && strcmp (sys->arg, "}")) {
- X found = FALSE;
- X for (i = 0; i < MAX_SET_OPTIONS; i++)
- X if (!strcmp (sys->arg, options[i])) {
- X found = TRUE;
- X break;
- X }
- X if (!found)
- X report_progress (report, tsprintf ("\nsys_config(): Default value \
- X%s not recognized in %s", sys->arg, CONFIG), TRUE),
- X exit (4);
- X fscanf (config, "%s %s\n", line, line);
- X if (!re_strcmp (values[i], upcase (line), NULL))
- X report_progress (report, tsprintf ("\nsys_config(): %s not a valid \
- Xdefault value for %s in %s", line, options[i], CONFIG), TRUE),
- X exit (4);
- X strcpy (sys->lists[id].defaults.set_values[i], line);
- X }
- X }
- X if (feof (config) && strcmp (sys->arg, "}"))
- X report_progress (report, tsprintf ("\nsys_config(): Missing '}' for \
- X'default' for list %s in %s", sys->lists[id].alias, CONFIG), TRUE),
- X exit (4);
- X }
- X else if (!strcmp (cmd, "precedence"))
- X sscanf (args, "%s", sys->mail.precedence);
- X else if (!strcmp (cmd, "fax"))
- X strcpy (sys->fax.prog, args);
- X else if (!strcmp (cmd, "archive")) {
- X /* USER CONTRIBUTED CODE: Warren Burstein
- X "archive list dir spec [farch-dir] [password] [digest]"
- X
- X dir must be an absolute path
- X
- X farch-dir should be relative to HOMEDIR/archives
- X so we can create all the INDEX files
- X
- X if you don't want digests but do want farch-dir, set the field
- X to anything but digest, if you don't want farch-dir just omit it.
- X */
- X char digest [MAX_LINE];
- X
- X RESET (digest);
- X sscanf (args, "%s ", sys->arg);
- X upcase (sys->arg);
- X id = get_list_id (sys->arg, sys, nlists);
- X if (id < 0)
- X report_progress (report, tsprintf ("\nsys_config(): Unrecognized list \
- Xname %s for 'archive' in %s", sys->arg, CONFIG), TRUE),
- X exit (4);
- X sys->lists[id].options |= ARCHIVE_LIST;
- X sscanf (args, "%s %s %s %s %s %s",
- X sys->arg, sys->lists[id].arch_dir, sys->lists[id].arch_spec,
- X sys->lists[id].farch_dir, sys->lists[id].arch_pass, digest);
- X
- X locase (sys->lists[id].arch_spec);
- X if (*sys->lists[id].arch_dir != '/') {
- X report_progress (report, tsprintf ("\nsys_config(): archive-dir for %s \
- Xdoesn't start with /",
- X sys->arg, CONFIG), TRUE),
- X exit (4);
- X }
- X
- X if (*sys->lists[id].farch_dir == '/') {
- X report_progress (report, tsprintf ("\nsys_config(): farch-dir for %s \
- Xstarts with /",
- X sys->arg, CONFIG), TRUE),
- X exit (4);
- X }
- X
- X if (*sys->lists[id].farch_dir == '-' || *sys->lists[id].farch_dir == EOS)
- X sprintf (sys->lists[id].farch_dir, DEFAULT_ARCHIVE);
- X
- X if (!strcmp (sys->lists[id].arch_pass, "-"))
- X RESET (sys->lists[id].arch_pass);
- X
- X if (!strcmp (locase (digest), "digest"))
- X sys->lists[id].options |= ARCHIVE_DIGEST;
- X }
- X else if (!strcmp (cmd, "unix_cmd")) {
- X sscanf (args, "%s", sys->arg);
- X upcase (sys->arg);
- X id = get_list_id (sys->arg, sys, nlists);
- X if (id < 0)
- X report_progress (report, tsprintf ("\nsys_config(): Unrecognized list \
- Xname %s for 'unix_cmd' in %s", sys->arg, CONFIG), TRUE),
- X exit (4);
- X RESET (arg);
- X sscanf (args, "%s %s", sys->arg, arg);
- X if (arg[0] == EOS || arg[0] == '#' || arg[0] == '\'')
- X report_progress (report, tsprintf ("\nsys_config(): Missing or invalid \
- Xpassword %s for 'unix_cmd' in %s", arg, CONFIG), TRUE),
- X exit (4);
- X if ((unix_cmd = (_CMDS *) malloc (sizeof (*unix_cmd))) == NULL)
- X report_progress (report, tsprintf ("\nsys_config(): malloc() failed \
- Xduring 'unix_cmd' in %s", CONFIG), TRUE),
- X exit (11);
- X strcpy (unix_cmd->password, arg);
- X upcase (unix_cmd->password);
- X RESET (arg);
- X sscanf (args, "%s %s %s", sys->arg, sys->arg, arg);
- X if (arg[0] == EOS || arg[0] == '#' || arg[0] == '\'')
- X report_progress (report, tsprintf ("\nsys_config(): Missing or invalid \
- Xcommand name %s for 'unix_cmd' in %s", arg, CONFIG), TRUE),
- X exit (4);
- X strcpy (unix_cmd->name, arg);
- X upcase (unix_cmd->name);
- X start = strchr (args, '\'');
- X end = strrchr (args, '\'');
- X if (!start || !end || start == end)
- X report_progress (report, tsprintf ("\nsys_config(): Missing ''' for \
- X'unix_cmd' in %s",
- X CONFIG), TRUE),
- X exit (4);
- X if (! (unix_cmd->cmd =
- X (char *) malloc ((abs (end - start - 1) + 1) * sizeof (char))))
- X report_progress (report, tsprintf ("\nsys_config(): malloc() failed \
- Xduring 'unix_cmd' in %s", CONFIG), TRUE),
- X exit (11);
- X strncpy (unix_cmd->cmd, start + 1, abs (end - start - 1));
- X unix_cmd->cmd[abs (end - start - 1)] = EOS;
- X if (!(comment = strchr (args, '#')))
- X report_progress (report, tsprintf ("\nsys_config(): Missing '#' for \
- X'unix_cmd' in %s",
- X CONFIG), TRUE),
- X exit (4);
- X if (! (unix_cmd->comment =
- X (char *) malloc ((strlen (comment + 1) + 1) * sizeof (char))))
- X report_progress (report, tsprintf ("\nsys_config(): malloc() failed \
- Xduring 'unix_cmd' in %s", CONFIG), TRUE),
- X exit (11);
- X strcpy (unix_cmd->comment, comment + 1);
- X unix_cmd->next = sys->lists[id].unix_cmds;
- X sys->lists[id].unix_cmds = unix_cmd;
- X }
- X else
- X report_progress (report, tsprintf ("\nsys_config(): Unrecognized \
- Xdirective %s in %s", cmd, CONFIG), TRUE),
- X exit (4);
- X }
- X fclose (config);
- X config_owner_prefs (sys, nlists, report);
- X return nlists;
- X}
- X
- X/*
- X Get owner and manager preferences from OWNERSF.
- X
- X Enhanced by: Warren Burstein.
- X*/
- X
- Xvoid config_owner_prefs (SYS *sys, int nlists, FILE *report)
- X{
- X FILE *f;
- X char registered_owner [MAX_LINE];
- X char assigned_list [MAX_LINE];
- X char pref [MAX_OWNER_PREFS] [MAX_LINE];
- X char prefs [MAX_LINE];
- X int listid, i, *op;
- X
- X OPEN_FILE (f, OWNERSF, "r", "config_owner_prefs");
- X while (!feof (f)) {
- X assigned_list[0] = RESET (prefs);
- X fscanf (f, "%s %s", registered_owner, assigned_list);
- X upcase (assigned_list);
- X fgets (prefs, MAX_LINE - 2, f);
- X if (assigned_list [0] != EOS && registered_owner[0] != '#') {
- X for (i = 0; i < MAX_OWNER_PREFS; i++)
- X RESET (pref [i]);
- X sscanf (prefs, "%s %s %s %s %s %s %s %s", pref [0], pref [1], pref [2],
- X pref [3], pref [4], pref [5], pref [6], pref [7]);
- X if (!strcmp (assigned_list, "SERVER"))
- X op = &(sys->server.manager_prefs);
- X else if ((listid = get_list_id (assigned_list, sys, nlists)) >= 0)
- X op = &(sys->lists[listid].owner_prefs);
- X else
- X report_progress (report, tsprintf ("\nconfig_owner_prefs(): Unknown \
- Xlist %s in %s",
- X assigned_list, OWNERSF), TRUE),
- X exit (4);
- X for (i = 0; i < MAX_OWNER_PREFS && pref [i][0] != EOS; i++) {
- X /* Undocumented: also support -CCxxx systax: keni@oasys.dt.navy.mil */
- X char *pi = pref[i];
- X int pil = strlen (pi);
- X int neg = 0;
- X if (pi[0] == '-')
- X neg = 1,
- X --pil,
- X ++pi,
- X *op = ~*op;
- X if (!strncmp (pi, CCALL, pil))
- X *op |= ccall;
- X else if (!strncmp (pi, CCERRORS, pil))
- X *op |= ccerrors;
- X else if (!strncmp (pi, CCSUB, pil))
- X *op |= ccsub;
- X else if (!strncmp (pi, CCUNSUB, pil))
- X *op |= ccunsub;
- X else if (!strncmp (pi, CCSET, pil))
- X *op |= ccset;
- X else if (!strncmp (pi, CCREC, pil))
- X *op |= ccrec;
- X else if (!strncmp (pi, CCINFO, pil))
- X *op |= ccinfo;
- X else if (!strncmp (pi, CCSTAT, pil))
- X *op |= ccstat;
- X else if (!strncmp (pi, CCGET, pil))
- X *op |= ccget;
- X else if (!strncmp (pi, CCINDEX, pil))
- X *op |= ccindex;
- X else if (!strncmp (pi, CCLISTS, pil))
- X *op |= cclists;
- X else if (!strncmp (pi, CCRELEASE, pil))
- X *op |= ccrelease;
- X else if (!strncmp (pi, CCHELP, pil))
- X *op |= cchelp;
- X else if (!strncmp (pi, CCPRIVATE, pil))
- X *op |= ccprivate;
- X else if (!strncmp (pi, CCRUN, pil))
- X *op |= ccrun;
- X else if (pref [i][0] != EOS)
- X report_progress (report, tsprintf ("\nconfig_owner_prefs(): Unknown \
- Xpreference %s in %s",
- X pref [i], OWNERSF), TRUE),
- X exit (4);
- X if (neg)
- X *op = ~*op;
- X }
- X }
- X }
- X fclose (f);
- X}
- X
- X/*
- X Convert a string to lower case.
- X*/
- X
- Xchar *locase (char *s)
- X{
- X char *r = s;
- X while (*s != EOS) {
- X if (isupper (*s))
- X *s = (char) tolower (*s);
- X ++s;
- X }
- X return r;
- X}
- X
- X/*
- X Convert a string to upper case.
- X*/
- X
- Xchar *upcase (char *s)
- X{
- X char *r = s;
- X
- X while (*s != EOS) {
- X if (islower (*s))
- X *s = (char) toupper (*s);
- X ++s;
- X }
- X return r;
- X}
- X
- X/*
- X Replace all characters of the first word in 's' with "X".
- X*/
- X
- Xvoid shadow_password (char *s)
- X{
- X while (*s != EOS && isspace (*s)) /* Get to first word */
- X ++s;
- X if (*s != EOS)
- X while (!isspace (*s))
- X *s = 'X',
- X ++s;
- X}
- X
- X/*
- X Write messages and times to 'report' and stdout. If 'report_time'
- X is set to a negative value no leading newline is printed to 'report'.
- X NOTE: Use strftime(), if possible.
- X*/
- X
- Xvoid report_progress (FILE *report, char *s, int report_time)
- X{
- X#ifdef SYSLOG
- X char *buf;
- X int i, j;
- X
- X if (!(buf = (char *) malloc ((strlen (s) + 1) * sizeof (char))))
- X gexit (11);
- X strcpy (buf, s);
- X for (i = 0; i < strlen (buf); i++) {
- X if (buf [i] == '\n')
- X buf [i] = ' ';
- X if (buf [i] == '%' && buf [i + 1] != '%') {
- X if ((buf = (char *) realloc (buf, (strlen (buf) + 2) * sizeof (char))) ==
- X NULL)
- X gexit (11);
- X for (j = strlen (buf); j >= i; j--)
- X buf [j + 1] = buf [j];
- X ++i;
- X }
- X }
- X syslog (LOG_INFO, buf);
- X free ((char *) buf);
- X#else
- X extern BOOLEAN tty_echo;
- X# ifdef ultrix
- X time_t time_is = 0;
- X# else
- X long int time_is = 0;
- X# endif
- X struct tm *t;
- X
- X if (report) {
- X fprintf (report, "%s", s);
- X if (report_time) {
- X time (&time_is);
- X t = localtime (&time_is);
- X if (report_time > 0)
- X fprintf (report, "\n");
- X fprintf (report, "Time/Date: %2d:%.2d:%.2d, %2d/%.2d/%2d\n",
- X t->tm_hour, t->tm_min, t->tm_sec, t->tm_mon + 1, t->tm_mday,
- X t->tm_year);
- X }
- X fflush (report);
- X }
- X if (tty_echo) {
- X printf ("%s", s);
- X if (report_time)
- X printf ("\n");
- X fflush (stdout);
- X }
- X#endif
- X}
- X
- X/*
- X Start distribution. Call lower level routines; the algorithm is such that
- X this routine always looks at the beginning of each message when reading
- X into 'first_line', i.e. 'first_line' is always assigned a string of the form:
- X 'From emailaddress Date Time'
- X which is the universal convention for the start of every message. It calls
- X subscribed() to find out if the sender is subscribed and passes the
- X result to process_message(). Since the call to extract_sender() alters
- X 'first_line' to contain only the sender's email address a 'linecopy' is used.
- X When returning from process_message() we have already advanced to the
- X beginning of the next message, and 'linecopy' contains a string of the
- X above form; therefore we need to copy that back to 'first_line'.
- X*/
- X
- Xvoid distribute (FILE *mail, void (*process_message)(), FILE *report,
- X char *Subscribersf, char *Newsf, char *Peersf, char *Aliasesf,
- X BOOLEAN block_sem)
- X{
- X char first_line[MAX_LINE], linecopy[MAX_LINE];
- X BOOLEAN address_status;
- X
- X first_line[0] = RESET (linecopy);
- X while (!feof (mail))
- X if (first_line[0] != EOS)
- X address_status = extract_sender (first_line),
- X process_message ((char *) first_line, (char *) linecopy,
- X (BOOLEAN) address_status,
- X (BOOLEAN)
- X subscribed (report, first_line, Subscribersf, Newsf,
- X Peersf, Aliasesf, block_sem)),
- X strcpy (first_line, linecopy);
- X else /* Read the first line of the very first message */
- X fgets (first_line, MAX_LINE - 2, mail), /* 'From email Date Time' */
- X strcpy (linecopy, first_line);
- X}
- X
- X/*
- X Look for occurence of 'string' in 'substr' and return either TRUE or FALSE.
- X Look at the comments for defs.h for the syntax of 'substr'. A 'substr' of
- X ".*" matches everything.
- X*/
- X
- XBOOLEAN strinstr (char *substr, char *string)
- X{
- X char *substrcopy, *stringcopy;
- X extern FILE *report;
- X
- X substrcopy = (char *) malloc ((strlen (substr) + 1) * sizeof (char));
- X stringcopy = (char *) malloc ((strlen (string) + 1) * sizeof (char));
- X if (!substrcopy || !stringcopy)
- X report_progress (report, "\nstrinstr(): malloc() failed", TRUE),
- X gexit (11);
- X strcpy (substrcopy, substr);
- X strcpy (stringcopy, string);
- X upcase (substrcopy);
- X upcase (stringcopy);
- X if (re_strcmp (substrcopy, stringcopy, NULL) > 0) {
- X free ((char *) substrcopy);
- X free ((char *) stringcopy);
- X return TRUE;
- X }
- X free ((char *) stringcopy);
- X free ((char *) substrcopy);
- X return FALSE;
- X}
- X
- X/*
- X Given a file path, extract the file name. In the process, any command line
- X options or any characters separated from the filename are discarded.
- X*/
- X
- Xchar *extract_filename (char *s)
- X{
- X char *p, *r, *t = s, nchar = 0;
- X extern FILE *report;
- X
- X while (*t != EOS && *t != ' ' && *t != '\t') /* Get to delimiting char */
- X ++t;
- X while (t != s && *t != '/') /* Go back till / or the beginning of s */
- X ++nchar,
- X --t;
- X if (t != s || (*t == '/' && *(t + 1) != EOS))
- X --nchar,
- X ++t;
- X if (! (r = p = (char *) malloc ((nchar + 1) * sizeof (char))))
- X report_progress (report, "\nextract_filename(): malloc() failed", TRUE),
- X gexit (11);
- X *p = EOS;
- X while (*t != EOS && *t != ' ' && *t != '\t')
- X *(p++) = *(t++);
- X *p = EOS;
- X return r;
- X}
- X
- X/*
- X Recognize the command line parameters. It returns '?' on an unrecognized
- X option, ':' if an option requires an argument and the argument is missing,
- X or the recognized character itself. This code is a copyright of AT&T.
- X*/
- X
- X# define ERR(str, ch) if (opterr) \
- X fprintf (stderr, "%s%s%c\n", argv[0], str, ch);
- X
- X#ifdef linux
- Xint _getopt (int argc, char **argv, char *opts)
- X{
- X return getopt(argc, argv, opts);
- X}
- X#else
- Xint _getopt (int argc, char **argv, char *opts)
- X{
- X static int sp = 1;
- X register int c;
- X register char *cp;
- X extern int opterr, optind, optopt;
- X extern char *optarg;
- X
- X if (sp == 1)
- X if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
- X return EOF;
- X else if (!strcmp (argv[optind], "--")) {
- X optind++;
- X return EOF;
- X }
- X optopt = c = argv[optind][sp];
- X if (c == ':' || (cp = strchr (opts, c)) == NULL) {
- X ERR (": unknown option, -", c);
- X if (argv[optind][++sp] == '\0')
- X optind++,
- X sp = 1;
- X return '?';
- X }
- X if (*++cp == ':') {
- X if (argv[optind][sp+1] != '\0')
- X optarg = &argv[optind++][sp+1];
- X else if (++optind >= argc) {
- X ERR(": argument missing for -", c);
- X sp = 1;
- X return ':';
- X }
- X else
- X optarg = argv[optind++];
- X sp = 1;
- X }
- X else {
- X if (argv[optind][++sp] == '\0')
- X sp = 1,
- X optind++;
- X optarg = NULL;
- X }
- X return c;
- X}
- X#endif
- X
- X/*
- X Remove any extraneous characters from a name and convert it to lower
- X case with the first character of each word capitalized [currently disbled].
- X*/
- X
- Xchar *clean_name (char *s)
- X{
- X char *tok, *copy, *sep = " ", *line;
- X int j, l;
- X extern FILE *report;
- X
- X if (s [0] != EOS && s [strlen (s) - 1] == '\n')
- X s [strlen (s) - 1] = EOS;
- X if (! (line = (char *) malloc ((strlen (s) + 1) * sizeof (char))))
- X report_progress (report, "\nclean_name(): malloc() failed", TRUE),
- X gexit (11);
- X strcpy (line, s);
- X *s = EOS;
- X tok = strtok (line, sep);
- X while (tok) {
- X copy = tok;
- X while (*copy != EOS) { /* Remove extraneous characters */
- X if (! isalpha (*copy) && ! isspace (*copy) && ! isdigit (*copy) &&
- X *copy != '-' && *copy != '.' && *copy != '@') {
- X for (j = 0, l = strlen (copy); j < l; copy [j] = copy [j + 1], ++j);
- X continue;
- X }
- X ++copy;
- X }
- X locase (tok);
- X *tok = (char) toupper (*tok);
- X sprintf (s + strlen (s), " %s", tok);
- X tok = strtok (NULL, sep);
- X }
- X free ((char *) line);
- X return s;
- X}
- X
- X/*
- X Remove leading blanks and extraneous characters from a request.
- X*/
- X
- Xvoid clean_request (char *s)
- X{
- X while (isspace (*s))
- X sprintf (s, "%s", s + 1);
- X while (*s != EOS) {
- X if (*s < ' ' && *s != '\t' && *s != '\n' && *s != '\r')
- X *s = EOS;
- X ++s;
- X }
- X}
- X
- X/*
- X Identify the list that the request refers to. Before doing so, remove
- X any unnecessary blanks from the parameters. Also, check each parameter
- X for proper syntax.
- X*/
- X
- Xvoid get_list_name (char *params, char *list_name)
- X{
- X int i;
- X char *s, *r, *t;
- X char param [MAX_LINE];
- X extern FILE *report;
- X
- X if (! (r = s = (char *) malloc ((strlen (params) + 1) * sizeof (char))))
- X report_progress (report, "\nget_list_name(): malloc() failed", TRUE),
- X gexit (11);
- X strcpy (s, params);
- X param [0] = RESET (params);
- X for (i = 0; s[i] != EOS;)
- X if (isspace (s[i]) && isspace (s[i + 1]))
- X sprintf (s + i, "%s", s + i + 1);
- X else
- X i++;
- X do {
- X RESET (param);
- X sscanf (s, "%s", param);
- X s = s + strlen (param) + 1; /* Skip over space */
- X t = strpbrk (param, "*?/`");
- X if (t != NULL) {
- X if (t == param || (t != param && ! isalpha (*(t - 1)))) /* Invalid *,? */
- X *t = '#';
- X if (*t == '/') /* Invalid / */
- X *t = '%';
- X if (*t == '`') /* Invalid ` */
- X *t = '-';
- X }
- X sprintf (params + strlen (params), " %s", param);
- X } while (param[0] != EOS);
- X strcat (params, "\n");
- X free ((char *) r);
- X RESET (list_name);
- X sscanf (params, "%s", list_name);
- X upcase (list_name);
- X sprintf (params, "%s", params + strlen (list_name) + 1);
- X}
- X
- X/*
- X Free the current list of matched remote lists.
- X*/
- X
- Xvoid free_remote_matched (REMOTE **matched_rlists)
- X{
- X REMOTE *next;
- X
- X while (*matched_rlists) /* Free old list */
- X next = (*matched_rlists)->next,
- X free ((REMOTE *) *matched_rlists),
- X *matched_rlists = next;
- X}
- X
- X/*
- X Given a list name, return its index in the array of known lists. If the
- X list is a remote list, return nlists to signify this effect.
- X*/
- X
- Xint get_list_id (char *list_name, SYS *sys, int nlists)
- X{
- X int i;
- X char *p, address [MAX_LINE];;
- X
- X free_remote_matched (&matched_rlists);
- X for (i = 0; i < nlists; i++) {
- X if (!strcmp (list_name, sys->lists[i].alias))
- X return i;
- X strcpy (address, sys->lists[i].address);
- X upcase (address);
- X if (!strcmp (list_name, address) && (p = strchr (list_name, '@'))) {
- X *p = EOS;
- X return i;
- X }
- X }
- X if (check_remote (rlists, list_name)) {
- X /* Store list name above all known lists */
- X strcpy (sys->lists[nlists].alias, list_name);
- X return nlists;
- X }
- X return -1;
- X}
- X
- X/*
- X Check whether 'list_name' is a remote list. Return a linked list
- X of matched records, or NULL. The list is stored in the global variable
- X 'matched_rlists'.
- X*/
- X
- XREMOTE *check_remote (REMOTE *rlists, char *list_name)
- X{
- X REMOTE *new;
- X char address [MAX_LINE];
- X extern FILE *report;
- X
- X while (rlists) {
- X strcpy (address, rlists->address);
- X upcase (address);
- X if (!strcmp (list_name, rlists->alias) ||
- X !strcmp (list_name, address)) {
- X if ((new = (REMOTE *) malloc (sizeof (*new))) == NULL)
- X report_progress (report, "\ncheck_remote(): malloc() failed", TRUE),
- X gexit (11);
- X memcpy ((char *) new, (char *) rlists, sizeof (*new));
- X new->next = matched_rlists;
- X matched_rlists = new;
- X }
- X rlists = rlists->next;
- X }
- X return matched_rlists;
- X}
- X
- Xvoid setup_string (char *s, char *alias, char *filename)
- X{
- X RESET (s);
- X SETUP_STRING;
- X}
- X
- X/*
- X Return the first occurence of 'sub' in 'src', or NULL if not found.
- X*/
- X
- Xchar *_strstr (char *src, char *sub)
- X{
- X if (src == NULL || sub == NULL)
- X return NULL;
- X while (*src != EOS) {
- X if (!strncmp (src, sub, strlen (sub)))
- X return src;
- X ++src;
- X }
- X return NULL;
- X}
- X
- X/*
- X Shrink a file so that it contains a maximum of MAX_FILE_LENGTH entries in it.
- X*/
- X
- Xvoid shrink (char *s)
- X{
- X struct stat buf;
- X char *tmpmsg;
- X
- X if (s[0] == EOS || stat (s, &buf))
- X return;
- X syscom ("tail -%d %s > %s", MAX_FILE_LENGTH, s,
- X (tmpmsg = mystrdup (tmpnam (NULL))));
- X mv (tmpmsg, s);
- X free ((char *) tmpmsg);
- X}
- X
- X/*
- X Verify that part 'i' (of a file split into different parts by farch)
- X is in 's'.
- X*/
- X
- XBOOLEAN requested_part (char *s, int i)
- X{
- X char buf [80];
- X char copy [MAX_LINE];
- X
- X strncpy (copy, s, MAX_LINE - 1);
- X copy [MAX_LINE - 1] = EOS;
- X do {
- X RESET (buf);
- X sscanf (copy, "%s", buf);
- X sprintf (copy, "%s", strchr (copy, buf[0]) + strlen (buf));
- X if (atoi (buf) == i)
- X return TRUE;
- X } while (buf[0] != EOS);
- X return FALSE;
- X}
- X
- X/*
- X Free the REMOTE linked list.
- X*/
- X
- Xvoid free_remote (REMOTE **rlists)
- X{
- X REMOTE *next;
- X
- X while (*rlists)
- X next = (*rlists)->next,
- X free ((REMOTE *) *rlists),
- X *rlists = next;
- X *rlists = NULL;
- X}
- X
- X/*
- X Use my_system() when either list and listproc use TELNET and there is
- X an indication that the sessions do not exit.
- X*/
- X
- Xint my_system (char *s)
- X{
- X FILE *f;
- X int pid, status;
- X char line [MAX_LINE], *r;
- X extern SYS sys;
- X
- X if (strcmp ((r = extract_filename (s)), "telnet")) {
- X status = system (s);
- X free ((char *) r);
- X return status;
- X }
- X free ((char *) r);
- X strcat (s, " &"); /* Only telnet runs in the background */
- X status = system (s);
- X if (status > 127)
- X return status;
- X sleep (5);
- X if (sys.options & BSD_PS)
- X system ("ps -gx | grep telnet | grep -v \"grep telnet\" \
- X | grep -v telnetd > ./telnet");
- X else if (sys.options & SYSV_PS)
- X system ("ps -ef | grep telnet | grep -v \"grep telnet\" \
- X | grep -v telnetd > ./telnet");
- X if ((f = fopen ("./telnet", "r")) == NULL)
- X return -1;
- X while (! feof (f)) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, f);
- X if (line[0] != EOS)
- X sscanf (line, "%d", &pid),
- X sleep (15),
- X kill (pid, SIGHUP);
- X }
- X fclose (f);
- X unlink ("./telnet");
- X return status;
- X}
- X
- X/* Change history (by Bob Boyd)
- X21-Aug-1991 RLB change parameter scanning for "list" lines in the
- X config file so that "-" characters in the list-alias
- X are ignored when looking for the beginning of the
- X list parameters [tasos: I defined my own strstr()]
- X*/
- X
- X/*
- X Remove the message identified as 'tag_to_remove' from the specified 'file'.
- X Return TRUE if successful, FALSE if the message was not located.
- X*/
- X
- XBOOLEAN remove_msg (char *file, int tag_to_remove, FILE *report)
- X{
- X FILE *in, *out;
- X char prev_line [MAX_LINE];
- X char line [MAX_LINE];
- X char match [MAX_LINE];
- X char *tmp_moderated_f;
- X BOOLEAN copy = FALSE, message_found = FALSE;
- X int tag;
- X
- X mv (file, (tmp_moderated_f = mystrdup (tmpnam (NULL))));
- X chmod (tmp_moderated_f, 416); /* 640 */
- X OPEN_FILE (in, tmp_moderated_f, "r", "remove_msg");
- X OPEN_FILE (out, file, "w", "remove_msg");
- X prev_line[0] = RESET (line);
- X while (!feof (in)) {
- X if (!strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)) &&
- X !copy)
- X RESET (prev_line),
- X copy = TRUE;
- X strcpy (match, "\\1");
- X if (re_strcmp (MESSAGE_TAG, line, match) > 0) { /* Get tag # */
- X sprintf (line, "%s", line + strlen (match));
- X sscanf (line, "%d", &tag);
- X sprintf (line, "%s%d\n", match, tag);
- X if (tag_to_remove == tag)
- X message_found = TRUE,
- X copy = FALSE;
- X }
- X if (copy && prev_line[0] != EOS)
- X fprintf (out, "%s", prev_line);
- X strcpy (prev_line, line);
- X RESET (line);
- X fgets (line, MAX_LINE - 2, in);
- X }
- X if (copy && prev_line[0] != EOS)
- X fprintf (out, "%s", prev_line);
- X fclose (in);
- X fclose (out);
- X unlink (tmp_moderated_f);
- X free ((char *) tmp_moderated_f);
- X return message_found;
- X}
- X
- X/*
- X Read the parameters from 'line' that follow 'request' in 'line',
- X and possibly from lines below in the 'mail' file, if 'line' ends
- X with &. Continuation lines should always end with '&' and no
- X trailing blanks or any other characters except new-line.
- X 'params' should end with a \n.
- X*/
- X
- Xvoid read_params (char *line, char *params, char *request, FILE *mail,
- X FILE *report)
- X{
- X char l [MAX_LINE];
- X
- X sprintf (params, "%s", line + strlen (request));
- X if (params [strlen (params) - 1] == '\n')
- X params [strlen (params) - 1] = EOS; /* Remove trailing \n */
- X RESET (l);
- X while (!feof (mail) &&
- X strncmp (l, START_OF_MESSAGE, strlen (START_OF_MESSAGE)) &&
- X params [0] != EOS && params [strlen (params) - 1] == '&') {
- X params [strlen (params) - 1] = EOS; /* Replace & */
- X RESET (l);
- X fgets (l, MAX_LINE - 2, mail);
- X if (l [0] != EOS &&
- X strncmp (l, START_OF_MESSAGE, strlen (START_OF_MESSAGE))) {
- X if (report)
- X report_progress (report, l, FALSE);
- X l [strlen (l) - 1] = EOS, /* Remove trailing \n */
- X strcat (params, l);
- X }
- X }
- X strcat (params, "\n");
- X if (!strncmp (l, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))
- X fseek (mail, -strlen (l), SEEK_CUR); /* Move back to beginning of new msg */
- X}
- X
- X/*
- X Open and lock file. It returns the opened file descriptor, or
- X CANT_OPEN or CANT_LOCK.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- Xint lock_file (char *file, int flag, int mode, BOOLEAN delay)
- X{
- X#ifdef NO_LOCKS
- X return 0;
- X#else
- X int count, fd, lock;
- X
- X if ((fd = open (file, flag, mode)) < 0)
- X return CANT_OPEN;
- X for (count = 0; (lock = lockf (fd, F_TLOCK, 0)) && (count < 180) && delay;
- X ++count, sleep (1));
- X if (lock) {
- X close (fd);
- X return CANT_LOCK;
- X }
- X return fd;
- X#endif
- X}
- X
- X/*
- X Unlock and close the specified file descriptor.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- Xvoid unlock_file (int fd)
- X{
- X#ifndef NO_LOCKS
- X if (fd >= 0)
- X lockf (fd, F_ULOCK, 0),
- X close (fd);
- X#endif
- X}
- X
- X/*
- X Write to a non-blocking file descriptor.
- X*/
- X
- Xlong int write_to_fd (int fd, char *buf, long int bytes_to_write)
- X{
- X long int bytes_written, total_bytes = 0;
- X extern FILE *report;
- X char ch;
- X int mask;
- X
- X errno = 0;
- X#ifndef NO_ABORT_OP
- X if (fcntl (fd, F_SETFL, (mask = fcntl (fd, F_GETFL, 0)) | O_NDELAY) < 0
- X# ifdef ENOTSOCK
- X && errno != ENOTSOCK
- X# endif
- X )
- X report_progress (report, tsprintf ("\nwrite_to_fd(): fcntl() failed: \
- Xerrno %d", errno), TRUE);
- X#endif
- X while ((bytes_written = write (fd, buf, bytes_to_write)) < bytes_to_write) {
- X if (bytes_written < 0 && errno
- X#ifdef ERESTART
- X && errno != ERESTART
- X#endif
- X ) {
- X char error [256];
- X sprintf (error, "\nwrite_to_fd(): ");
- X switch (errno) {
- X case EWOULDBLOCK:
- X#if (EWOULDBLOCK != EAGAIN)
- X case EAGAIN:
- X#endif
- X case EINTR:
- X#if defined (GO_INTERACTIVE) && !defined (NO_ABORT_OP)
- X if (recv (fd, &ch, 1, MSG_OOB | MSG_PEEK) > 0)
- X goto abort;
- X#endif
- X continue;
- X case EBADF: strcat (error, "Bad file number"); break;
- X case EFAULT: strcat (error, "Bad address"); break;
- X case EFBIG: strcat (error, "File limit reached"); break;
- X case EINVAL: strcat (error, "Negative seek pointer"); break;
- X case EIO: strcat (error, "I/O error"); break;
- X case ENOSPC: strcat (error, "No space left on device"); break;
- X case ENXIO: strcat (error, "No such device or address"); break;
- X case ERANGE: sprintf (error + strlen (error), "Bytes to write (%ld) \
- Xout of range", bytes_to_write); break;
- X case EPIPE: sprintf (error, "Client disappeared"); break;
- X#ifdef ENETRESET
- X case ENETRESET: strcat (error, "Network dropped connection"); break;
- X#endif
- X default: sprintf (error + strlen (error), "Error number %d", errno);
- X }
- X report_progress (report, error, TRUE);
- X if (bytes_written > 0)
- X total_bytes += bytes_written;
- X#ifndef NO_ABORT_OP
- X if (fcntl (fd, F_SETFL, mask) < 0
- X# ifdef ENOTSOCK
- X && errno != ENOTSOCK
- X# endif
- X )
- X report_progress (report, tsprintf ("\nwrite_to_fd(): fcntl() failed: \
- Xerrno %d", errno), TRUE);
- X#endif
- X return (total_bytes > 0 ? -total_bytes : -1);
- X }
- X if (bytes_written > 0)
- X bytes_to_write -= bytes_written,
- X total_bytes += bytes_written,
- X buf += bytes_written;
- X errno = 0;
- X }
- X if (bytes_written > 0)
- X total_bytes += bytes_written;
- X abort:
- X#ifndef NO_ABORT_OP
- X if (fcntl (fd, F_SETFL, mask) < 0
- X# ifdef ENOTSOCK
- X && errno != ENOTSOCK
- X# endif
- X )
- X report_progress (report, tsprintf ("\nwrite_to_fd(): fcntl() failed: \
- Xerrno %d", errno), TRUE);
- X#endif
- X return total_bytes;
- X}
- X
- X/*
- X Improved mkdir - builds all parents of full_path if needed.
- X If a mkdir fails, or a component of the directory exists but
- X is not a directory, return FALSE and store a description in report_msg.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- XBOOLEAN mkdir1 (char *full_path, char *report_msg, char *mask)
- X{
- X BOOLEAN first = TRUE;
- X char *p = full_path, d[MAX_LINE], dir[MAX_LINE], head[MAX_LINE];
- X struct stat st;
- X
- X RESET (head);
- X while (get_field (&p, '/', d)) {
- X if (first) {
- X first = FALSE;
- X
- X if (d[0] == EOS) {
- X strcpy (head, "/");
- X continue;
- X }
- X }
- X
- X sprintf (dir, "%s%s", head, d);
- X sprintf (head, "%s/", dir);
- X
- X if (stat (dir, &st)) {
- X if (mkdir (dir, 0755 & (0755 ^ otoi (mask)))) {
- X sprintf (report_msg, "mkdir1(%s): mkdir %s failed, errno %d\n",
- X full_path, dir, errno);
- X return FALSE;
- X }
- X }
- X else if ((st.st_mode & S_IFMT) != S_IFDIR) {
- X sprintf (report_msg, "mkdir1: %s is not a directory", dir);
- X return FALSE;
- X }
- X }
- X return TRUE;
- X}
- X
- X/*
- X Convert an octal number stored in a string to integer.
- X*/
- X
- Xint otoi (char *s)
- X{
- X int i, n;
- X
- X n = 0;
- X for (i = 0; s[i] >= '0' && s[i] <= '7'; ++i)
- X n = 8 * n + (s[i] - '0');
- X return n;
- X}
- X
- X/*
- X Find a field in *src ending with "sep". Leave src pointing at char after sep,
- X store field in dst. If src points at end of string, return FALSE. If src
- X points at a separator, make dst a null string.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- XBOOLEAN get_field (char **src, char sep, char *dst)
- X{
- X char *s = *src;
- X int len;
- X
- X if (**src == EOS)
- X return FALSE;
- X
- X while (**src != EOS && **src != sep)
- X ++*src;
- X
- X if (*src == s) {
- X *dst = EOS;
- X if (**src != EOS)
- X ++*src;
- X return TRUE;
- X }
- X
- X len = *src - s;
- X (void) strncpy (dst, s, len);
- X dst[len] = EOS;
- X
- X if (**src != EOS) /* advance past separator */
- X ++*src;
- X
- X return TRUE;
- X}
- X
- X/*
- X Make the directory for dirf (a DIR file) and create/update all
- X necessary INDEX files.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burstein
- X*/
- X
- XBOOLEAN make_indexes (char *dirf, char *farch_dir, char *password, char *error,
- X char *mask)
- X{
- X char dirname [MAX_LINE], *p, *q;
- X struct dirmatch {
- X char *s;
- X BOOLEAN match;
- X } *dirs;
- X int n_dirs, i, j;
- X extern FILE *report;
- X
- X /* Get the directory that INDEX/DIR is in and make it if needed. */
- X strcpy (dirname, dirf);
- X if (p = strrchr (dirname, '/'))
- X *p = EOS;
- X if (!mkdir1 (dirname, error, mask))
- X return FALSE;
- X
- X /* The number of dirs is one higher than the number of slashes. Add one
- X more for the top level directory, ARCHIVE_DIR */
- X for (p = farch_dir, n_dirs = 2; *p != EOS; p++)
- X if (*p == '/')
- X ++n_dirs;
- X
- X if (! (dirs = (struct dirmatch *) calloc (n_dirs, sizeof (dirs[0]))))
- X report_progress (report, "\nmake_indexes(): calloc() failed", TRUE),
- X gexit (11);
- X
- X if (! (dirs[0].s =
- X (char *) malloc ((strlen (ARCHIVE_DIR) +
- X strlen (DEFAULT_ARCHIVE) + 2) * sizeof (char))))
- X report_progress (report, "\nmake_indexes(): malloc() failed", TRUE),
- X gexit (11);
- X sprintf (dirs[0].s, "%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE);
- X
- X for (i = 1, p = farch_dir; i < n_dirs; i++) {
- X int len;
- X
- X /* Find end of the directory - slash or end of string */
- X for (q = p; *q != EOS && *q != '/'; q++);
- X len = q - p;
- X
- X if (i == 1) {
- X if (! (dirs[i].s =
- X (char *) malloc ((strlen (ARCHIVE_DIR) + len + 2) *
- X sizeof (char))))
- X report_progress (report, "\nmake_indexes(): malloc() failed", TRUE),
- X gexit (11);
- X sprintf (dirs[i].s, "%s/%.*s", ARCHIVE_DIR, len, p);
- X }
- X else {
- X if (! (dirs[i].s = (char *) malloc ((strlen (dirs[i - 1].s) + len + 2) *
- X sizeof (char))))
- X report_progress (report, "\nmake_indexes(): malloc() failed", TRUE),
- X gexit (11);
- X sprintf (dirs[i].s, "%s/%.*s", dirs[i - 1].s, len, p);
- X }
- X
- X /* In case there are extra slashes, skip them */
- X for (; *q != EOS && *q == '/'; q++);
- X p = q;
- X
- X if (*p == EOS)
- X break; /* premature end of string - too many /'s */
- X }
- X
- X for (i = 0; i < n_dirs; i++) {
- X char indexf [MAX_LINE], dirf [MAX_LINE];
- X char line [MAX_LINE], arch [MAX_LINE], fullpath [MAX_LINE];
- X BOOLEAN missing;
- X FILE *fp;
- X
- X if (!dirs[i].s)
- X continue;
- X
- X /* Make INDEX and DIR files if not already there */
- X sprintf (indexf, "%s/%s", dirs[i].s, INDEX);
- X sprintf (dirf, "%s/%s", dirs[i].s, DIRF);
- X if (access (indexf, 0))
- X close (creat (indexf, 0644 & (0644 ^ otoi (mask))));
- X if (access (dirf, 0))
- X close (creat (dirf, 0644 & (0644 ^ otoi (mask))));
- X
- X /* Read the index file for i, set match fields to TRUE for j >= i if dir
- X for j is not in there. */
- X OPEN_FILE (fp, indexf, "r", "make_indexes");
- X
- X for (j = i; j < n_dirs; j++)
- X dirs[j].match = FALSE;
- X
- X while (!feof (fp)) {
- X arch[0] = fullpath[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, fp);
- X sscanf (line, "%s %s", arch, fullpath);
- X for (j = i; j < n_dirs; j++)
- X if (dirs[j].s && !strcmp (fullpath, dirs[j].s))
- X dirs[j].match = TRUE;
- X }
- X fclose (fp);
- X
- X /* Set 'missing' if any j doesn't have match set. Add lines if missing. */
- X missing = FALSE;
- X for (j = i; j < n_dirs; j++)
- X if (!dirs[j].match)
- X missing = TRUE;
- X
- X if (missing) {
- X OPEN_FILE (fp, indexf, "a", "make_indexes");
- X for (j = i; j < n_dirs; j++)
- X if (dirs[j].s && !dirs[j].match)
- X fprintf (fp, "%s %s %s\n", strrchr (dirs[j].s, '/') + 1, dirs[j].s,
- X (password ? password : ""));
- X fclose (fp);
- X }
- X free ((char *) dirs[i].s);
- X }
- X free ((struct dirmatch *) dirs);
- X return TRUE;
- X}
- X
- X/*
- X Insert 'nwords' to 's' starting at 'index' in 'words'. Return the total
- X length of the words inserted; blanks are inserted between words.
- X While making space for the new words, 'replace' so many number of characters.
- X*/
- X
- Xint insert_word (char *s, char **words, int nwords, int index, int replace)
- X{
- X int i, j, nbytes = 0;
- X char *c = NULL;
- X
- X for (i = 0; i < nwords; i++)
- X nbytes += strlen (words [index + i]);
- X if (nbytes < replace)
- X sprintf (s, "%s", s + replace - nbytes);
- X else
- X for (i = 0; i < nbytes - replace; i++)
- X for (c = s + strlen (s); c >= s + replace; c--)
- X *(c + 1) = *c;
- X for (i = 0, j = 0; i < nwords; i++)
- X memcpy (s + j, words [index + i], strlen (words [index + i])),
- X j += strlen (words [index + i]) + 1;
- X return nbytes;
- X}
- X
- X/*
- X Skip over words in a string and return the address of the beginning of the
- X requested word, or NULL if the word is beyond the end of string.
- X*/
- X
- Xchar *skip_to_word (char *s, int word)
- X{
- X BOOLEAN quote;
- X
- X while (*s != EOS && isspace (*s)) /* Skip to first word */
- X ++s;
- X while ((--word)) {
- X quote = FALSE;
- X while ((*s != EOS && !isspace (*s)) || (isspace (*s) && quote)) {
- X if (*s == '\"' || *s == '\'')
- X quote = !quote;
- X ++s;
- X }
- X while (*s != EOS && isspace (*s))
- X ++s;
- X }
- X if (*s == EOS)
- X return NULL;
- X return s;
- X}
- X
- X/*
- X Some UNIXes do not provide strdup().
- X*/
- X
- Xchar *mystrdup (char *s)
- X{
- X char *r;
- X
- X r = (char *) malloc ((strlen (s) + 1) * sizeof (char));
- X if (r)
- X strcpy (r, s);
- X return r;
- X}
- X
- X#ifdef NEED_VSPRINTF
- Xint vsprintf (dest, pat, args)
- Xchar *dest, *pat, *args;
- X{
- X FILE fakebuf;
- X
- X fakebuf._ptr = dest;
- X fakebuf._cnt = 32767;
- X#ifndef _IOSTRG
- X#define _IOSTRG 0
- X#endif
- X fakebuf._flag = _IOWRT|_IOSTRG;
- X _doprnt(pat, args, &fakebuf);
- X putc('\0', &fakebuf);
- X return 0;
- X}
- X#endif
- *-*-END-of-src/misc.c-*-*
- echo x - src/pqueue.c
- sed 's/^X//' >src/pqueue.c <<'*-*-END-of-src/pqueue.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | MAIL QUEUE PROCESSING ROUTINES |
- X | |
- X | Version 1.1 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X The 'system' mailmethod is used to attempt another delivery of the
- X specified files. If it cannot be done, the files are queued again.
- X*/
- X
- X#include <stdio.h>
- X#ifdef SYSLOG
- X# ifdef ultrix
- X# include <sys/syslog.h>
- X# else
- X# include <syslog.h>
- X# endif
- X#endif
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#if !defined (sequent) && !defined (__NeXT__) && !defined (__convex__) && \
- X !defined (apollo) && !defined (i386) && !defined (unknown_port)
- X# include <sys/termio.h>
- X#endif
- X#ifndef sun
- X# include <sys/ioctl.h>
- X#endif
- X#include <fcntl.h>
- X#include <signal.h>
- X#include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X#include "defs.h"
- X#include "struct.h"
- X#include "global.h"
- X#include "pqueue.h"
- X#if defined (__NeXT__) || defined (unknown_port)
- X# include "next.h"
- X#endif
- X
- X#ifdef __STDC__
- Xextern char *tsprintf (char *, ...);
- X#else
- Xextern char *tsprintf ();
- X#endif
- Xextern int _getopt (int, char **, char *);
- Xextern void init_signals (void);
- Xextern void catch_signals (void);
- Xextern void report_progress (FILE *, char *, int);
- Xextern BOOLEAN sysmail (char *);
- Xextern int lock_file (char *, int, int, BOOLEAN);
- Xextern void unlock_file (int);
- Xextern int otoi (char *);
- X
- Xvoid main (int, char **, char **);
- Xvoid usage (void);
- Xint gexit (int);
- X
- Xvoid main (int argc, char **argv, char **envp)
- X{
- X char *options = "eD", *mask;
- X int c, i, j;
- X FILE *f;
- X struct stat stat_buf;
- X extern int optind;
- X extern char *getenv();
- X
- X prog = argv[0];
- X while ((c = _getopt (argc, argv, options)) != EOF)
- X switch ((char) c) {
- X case 'e': tty_echo = TRUE; break;
- X case 'D': debug = TRUE; break;
- X case '?':
- X default:
- X usage ();
- X }
- X if (optind == argc)
- X fprintf (stderr, "pqueue: filename(s) missing.\n"),
- X exit (3);
- X if ((mask = getenv ("ULISTPROC_UMASK")))
- X umask (otoi (mask));
- X else
- X mask = "066",
- X umask (S_IRWXG|S_IRWXO); /* 600 */
- X#ifndef NO_LOCKS
- X if ((lfd = lock_file (PQUEUE_LOCK_FILE, O_RDWR, 0, FALSE)) < 0)
- X fprintf (stderr, "pqueue: Unable to lock %s. Aborting.\n",
- X PQUEUE_LOCK_FILE),
- X exit (1);
- X#endif
- X init_signals();
- X catch_signals();
- X
- X if (!tty_echo) {
- X j = -1;
- X#if defined (TIOCNOTTY) && defined (SIGTTOU) && defined (SIGTTIN)
- X if ((i = open ("/dev/tty", 2)) >= 0)
- X j = ioctl (i, TIOCNOTTY, 0),
- X close (i);
- X#endif
- X if (j < 0 &&
- X#ifdef svr4
- X setsid ()
- X#else
- X# ifdef SETPGRP_NEEDS_ARGS
- X setpgrp (0, 0)
- X# else
- X setpgrp ()
- X# endif
- X#endif
- X < 0)
- X report_progress (report, "WARNING: could not detach from tty", TRUE);
- X }
- X
- X#ifdef SYSLOG
- X openlog ("ListProcessor: pqueue", LOG_NDELAY
- X# ifndef i386
- X |LOG_NOWAIT
- X# endif
- X , SYSLOG);
- X# ifndef ultrix
- X setlogmask (LOG_UPTO (LOG_INFO));
- X# endif
- X#else
- X if ((report = fopen (REPORT_PQUEUE, "a")) == NULL)
- X fprintf (stderr, "pqueue: Could not open %s\n", REPORT_PQUEUE),
- X exit (1);
- X chmod (REPORT_PQUEUE, 384);
- X#endif
- X if ((f = fopen (PID_PQUEUE, "w")) != NULL)
- X fprintf (f, "%d", getpid()),
- X fclose (f);
- X signal (SIGINT, (void (*)()) gexit);
- X while (--argc >= optind) { /* main loop */
- X if (stat (argv [argc], &stat_buf))
- X report_progress (report, tsprintf ("\nmain(): Could not stat %s",
- X argv [argc]), TRUE),
- X gexit (1);
- X if (sysmail (argv [argc]))
- X if (unlink (argv [argc]))
- X report_progress (report, tsprintf ("\nmain(): Could not unlink file %s",
- X argv [argc]), TRUE),
- X gexit (1);
- X }
- X#ifdef SYSLOG
- X closelog ();
- X#else
- X fclose (report);
- X#endif
- X gexit (0);
- X}
- X
- Xvoid usage ()
- X{
- X fprintf (stderr, "Usage: pqueue [-e] [-D] <files>\n\
- X-e: Echo reports to the screen.\n\
- X-D: Turn debug on.\n");
- X exit (3);
- X}
- X
- X/*
- X Graceful exit. Remove pid file.
- X*/
- X
- Xint gexit (int exitcode)
- X{
- X unlink (PID_PQUEUE);
- X#ifndef NO_LOCKS
- X unlock_file (lfd);
- X#endif
- X exit (exitcode);
- X}
- *-*-END-of-src/pqueue.c-*-*
- echo x - src/regerror.c
- sed 's/^X//' >src/regerror.c <<'*-*-END-of-src/regerror.c-*-*'
- X/*
- X Tasos Kotsikonas (8/20/92): Changed function so that it stores the error
- X message to a global variable.
- X*/
- X
- X#include <stdio.h>
- Xchar *regerr;
- X
- Xvoid
- Xregerror(s)
- Xchar *s;
- X{
- X regerr = (char *) malloc ((strlen (s) + 1) * sizeof (char));
- X strcpy (regerr, s);
- X}
- *-*-END-of-src/regerror.c-*-*
- echo x - src/regex.c
- sed 's/^X//' >src/regex.c <<'*-*-END-of-src/regex.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | REGULAR EXPRESSIONS |
- X | |
- X | Version 1.0 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X Author: Tasos Kotsikonas (tasos@cs.bu.edu)
- X Disclaimer: All proper disclaimers apply; these include death, damage of any
- X kind to anything and anyone, and this kind of legal garbage.
- X Copying: You may copy, alter and redistribute this software as you see fit,
- X but you may not sell it for profit.
- X
- X Do pattern matching of two flavors: strict egrep(1), or extended egrep(1).
- X If the symbol egrep is #define'd below, strict egrep(1) syntax is used.
- X
- X The main routine is re_strcmp() which takes a regular expression, a
- X string to match against, and a string specifying which of the matched
- X subparts are to be used to form a new string -- if this string is NULL no
- X such action is taken.
- X
- X The new string is stored in the same space, so this string should be
- X long enough not to cause memory overwrites. To be able to do this match
- X substitution, the desired subparts of the regular expression should
- X be enclosed in ( and ). Each subpart is referenced to as \n where n is
- X a digit from 1 to 9.
- X
- X For example, the following call:
- X
- X strcpy (match, "\\2@\\1.UUCP");
- X re_strcmp ("[^!@]*!([^!@.]*)!([^!@]*)@.*", "GATE!HOP!USER@UUCP.SOME.COM",
- X match);
- X
- X will return TRUE and store in 'match' "USER@HOP.UUCP". See the man page
- X for Henry Spencer's routines included for more information.
- X
- X In extended mode, regular expressions may use the logical operators ~ (not),
- X & (and) and group expressions further with < and >. Because of the latter,
- X < and > may not be used in the ed(1) sense (\< is the default in the
- X context these routines were developed, and \> is useless in the same context).
- X To use any of these characters literally, precede them with a backslash (\).
- X
- X For example:
- X
- X re_strcmp ("~<.*\.COM|.*\.EDU>&~TASOS*", "TASOS@FOO.US", NULL)
- X
- X will return FALSE.
- X
- X re_strcmp() returns TRUE on success, FALSE if no match was found, or
- X -1 on error. In the latter case, the (char *) variable regerr contains the
- X actual error message.
- X
- X The system uses modified pattern matching routines written by Henry Spencer
- X (Copyright (c) 1986 by University of Toronto) -- actually only regerror.c
- X was modified. Many thanks and kudos to Henry for this wonderful piece of code.
- X
- X It is possible to use the ls(1) style wild characters * and ? by altering
- X the symbols STAR and QMARK below.
- X
- X It is also possible to turn off ed(1) style pattern matching (i.e. turn
- X off the meaning of [ ] { } etc.) by using the function escape_re() where
- X marked with ###.
- X
- X To test these routines compile with -Dtest and run independently as follows:
- X
- X % cc -Dtest -I. regexp.c regsub.c regex.c regerror.c
- X % a.out 'regular-expression' file [match]
- X
- X NOTICE: Spencer's $ matches the enf-of-line without mathing a newline
- X character. When compiling with -Dtest, $ is replaced with .$
- X*/
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <string.h>
- X#include <ctype.h>
- X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
- X && !defined (sequent) && !defined (unknown_port)
- X# include <malloc.h>
- X#endif
- X#include "regexp.h"
- X
- X/*
- X#define egrep Define it if you want to use strict egrep(1) regular expressions
- X*/
- X
- X#define MAXLENGTH 1024 /* Maximum length of each regular expression */
- X#define EOS '\0'
- X
- Xint re_strcmp (char *, char *, char *);
- Xvoid escape_re (char *);
- Xint prevch (char *, char *);
- Xint nextch (char *);
- X
- X#ifdef test
- Xint main (int, char **);
- Xvoid workaround (char *);
- X#else
- Xextern void report_progress (FILE *, char *, int);
- Xextern FILE *report;
- X#endif
- X#ifndef egrep
- Xchar *convert_re (char *);
- Xint icp (int);
- Xint push (int);
- Xint pop (void);
- Xint do_op (int, int, int);
- Xvoid pop_op (void);
- Xint new_op (int);
- Xint eval (void);
- Xint isop (char *, char *);
- X
- X# define STAR "*" /* If ".*" then the meaning is that of ls(1) */
- X# define QMARK "?" /* If "." then the meaning is that of ls(1) */
- X# define LGROUPCH '<' /* Avoid ( and ) */
- X# define RGROUPCH '>'
- X# define OR 1 /* Operators should be > 0 */
- X# define AND 2
- X# define NOT 3
- X# define LPAREN 4
- X# define RPAREN 5
- X
- Xtypedef struct _operator_stack {
- X int op;
- X int isp; /* In-stack priority */
- X struct _operator_stack *next, *prev;
- X} OPERATOR_STACK;
- X
- Xtypedef struct _operand_stack {
- X int val;
- X struct _operand_stack *next, *prev;
- X} OPERAND_STACK;
- X
- XOPERATOR_STACK *op_top;
- XOPERAND_STACK *val_top;
- X#endif
- X
- Xint pliteral, literal, nliteral;
- X
- Xextern char *regerr;
- X
- X#ifdef test
- Xint main (int argc, char **argv)
- X{
- X FILE *f;
- X char s [1024], matches [1024];
- X int match;
- X
- X if (argc < 3)
- X printf ("Usage: %s 'regular-expression' file [match]\n", argv[0]), exit (1);
- X if ((f = fopen (argv[2], "r")) == NULL)
- X printf ("%s: ", argv[2]), fflush (stdout), perror (""), exit (1);
- X while (!feof (f)) {
- X memset (s, EOS, sizeof (s));
- X fgets (s, sizeof (s) - 1, f);
- X if (argc > 3)
- X strcpy (matches, argv[3]);
- X if ((match = re_strcmp (argv[1], s, matches)) > 0)
- X printf ("MATCHES:%s\n", matches),
- X printf ("%s", s);
- X else if (match < 0)
- X printf ("Error in regular expression\n"),
- X exit (1);
- X }
- X fclose (f);
- X exit (0);
- X}
- X#endif
- X
- X/*
- X Check 'subject' againt the 'regexpr'. Return 1 on match, 0 if no match,
- X or -1 on error. To negegate a regular expression precede it with '~';
- X multiple regular expressions are separated by '|' or '&' (logical OR and
- X AND) and may be grouped with LGROUPCH and RGROUPCH. To escape the key
- X characters LGROUPCH * ? | & RGROUPCH use \.
- X*/
- X
- Xint re_strcmp (char *regexpr, char *subject, char *result)
- X{
- X char *re, *readdr, *s, _re[MAXLENGTH], matches [1024], *error;
- X int op, i;
- X regexp *cmp;
- X
- X s = (char *) malloc ((strlen (regexpr) + 1) * sizeof (char));
- X strcpy (s, regexpr);
- X#ifdef test
- X workaround (s); /* Work around bugs with Spencer's code */
- X#endif
- X#ifndef egrep
- X/*### Do not escape ed(1) special characters.
- X escape_re (s);
- X*/
- X readdr = re = convert_re (s);
- X#else
- X re = s;
- X#endif
- X do {
- X#ifndef egrep
- X if ((op = isop (re, readdr))) {
- X if (new_op (op)) {
- X eval (); /* Empty stacks */
- X return -1;
- X }
- X ++re;
- X }
- X else
- X#endif
- X {
- X i = 0;
- X while (*re != EOS && i < MAXLENGTH
- X#ifndef egrep
- X && !isop (re, readdr)
- X#endif
- X )
- X _re [i++] = *re,
- X ++re;
- X if (i == MAXLENGTH) /* Overflow */
- X return -1;
- X _re [i] = EOS;
- X if (! (cmp = (regexp *) regcomp (_re))) {
- X#ifndef test
- X error = (char *) malloc ((strlen (regerr) + strlen (_re) + 7) *
- X sizeof (char));
- X sprintf (error, "RE %s: %s\n", _re, regerr);
- X report_progress (report, error, 1);
- X#else
- X printf ("RE %s: %s\n", _re, regerr);
- X#endif
- X free ((char *) regerr);
- X free ((char *) error);
- X#ifndef egrep
- X eval (); /* Empty stacks */
- X free ((char *) readdr);
- X#endif
- X return -1;
- X }
- X if (regexec (cmp, subject)) {
- X if (result)
- X regsub (cmp, result, matches),
- X strcpy (result, matches);
- X free ((regexp *) cmp);
- X#ifndef egrep
- X push (1);
- X#else
- X free ((char *) s);
- X return 1;
- X#endif
- X }
- X else {
- X free ((regexp *) cmp);
- X#ifndef egrep
- X push (0);
- X#else
- X free ((char *) s);
- X return 0;
- X#endif
- X }
- X }
- X } while (*re != EOS);
- X#ifndef egrep
- X free ((char *) readdr);
- X free ((char *) s);
- X return eval ();
- X#endif
- X}
- X
- X/*
- X Scan 's' and escape the following characters: [ ] < > { } , ; . ^ $ + -
- X for regular expression matching.
- X
- X To be used if one does not want ed(1) style pattern matching. Currently, this
- X function is unused.
- X*/
- X
- Xvoid escape_re (char *s)
- X{
- X char *r;
- X
- X while (*s != EOS) {
- X switch (*s) {
- X case '[': case ']': case '<': case '>': case '+': case '-':
- X case ';': case ',': case '.': case '^': case '$': case '{': case '}':
- X r = s + strlen (s); /* Start from the end */
- X while (r != s)
- X *(r + 1) = *r,
- X --r;
- X *(r + 1) = *r;
- X *r = '\\';
- X ++s;
- X break;
- X }
- X ++s;
- X }
- X}
- X
- X/*
- X Possibly convert the wild characters * and ? to ed(1) regular expressions.
- X Handle escaped characters.
- X*/
- X
- X#ifndef egrep
- Xchar *convert_re (char *re)
- X{
- X char *r, *b = re;
- X int i = 0;
- X
- X if (! (r = (char *) malloc (sizeof (char))))
- X# ifndef test
- X report_progress (report, "\nconvert_re(): malloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "convert_re(): malloc() failed\n"),
- X exit (11);
- X# endif
- X while (*re != EOS) {
- X prevch (re, b); /* See if *re is literal */
- X switch (*re) {
- X case '\\':
- X if (re != b && literal) {
- X if (! (r = (char *) realloc (r, (i + 2) * sizeof (char))))
- X# ifndef test
- X report_progress (report, "\nconvert_re(): realloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "convert_re(): realloc() failed\n"),
- X exit (11);
- X# endif
- X strncpy (r + i, "\\\\", 2);
- X i += 2;
- X }
- X break;
- X case '?': /* Match one character */
- X if (re != b && literal) { /* Literal */
- X if (! (r = (char *) realloc (r, (i + 1) * sizeof (char))))
- X# ifndef test
- X report_progress (report, "\nconvert_re(): realloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "convert_re(): realloc() failed\n"),
- X exit (11);
- X# endif
- X *(r + i) = *re;
- X ++i;
- X }
- X else {
- X if (! (r = (char *) realloc (r, (i + strlen (QMARK)) * sizeof (char))))
- X# ifndef test
- X report_progress (report, "\nconvert_re(): realloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "convert_re(): realloc() failed\n"),
- X exit (11);
- X# endif
- X strncpy (r + i, QMARK, strlen (QMARK));
- X i += strlen (QMARK);
- X }
- X break;
- X case '*': /* Match multiple characters */
- X if (re != b && literal) { /* Literal */
- X if (! (r = (char *) realloc (r, (i + 2) * sizeof (char))))
- X# ifndef test
- X report_progress (report, "\nconvert_re(): realloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "convert_re(): realloc() failed\n"),
- X exit (11);
- X# endif
- X strncpy (r + i, "\\*", 2);
- X i += 2;
- X }
- X else {
- X if (! (r = (char *) realloc (r, (i + strlen (STAR)) * sizeof (char))))
- X# ifndef test
- X report_progress (report, "\nconvert_re(): realloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "convert_re(): realloc() failed\n"),
- X exit (11);
- X# endif
- X strncpy (r + i, STAR, strlen (STAR));
- X i += strlen (STAR);
- X }
- X break;
- X default:
- X if (re != b && literal) { /* carry over */
- X if (! (r = (char *) realloc (r, (i + 2) * sizeof (char))))
- X# ifndef test
- X report_progress (report, "\nconvert_re(): realloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "convert_re(): realloc() failed\n"),
- X exit (11);
- X# endif
- X *(r + i) = *(re - 1);
- X *(r + i + 1) = *re;
- X i += 2;
- X }
- X else {
- X if (! (r = (char *) realloc (r, (i + 1) * sizeof (char))))
- X# ifndef test
- X report_progress (report, "\nconvert_re(): realloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "convert_re(): realloc() failed\n"),
- X exit (11);
- X# endif
- X *(r + i) = *re;
- X ++i;
- X }
- X }
- X ++re;
- X }
- X if (! (r = (char *) realloc (r, (i + 1) * sizeof (char))))
- X# ifndef test
- X report_progress (report, "\nconvert_re(): realloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "convert_re(): realloc() failed\n"),
- X exit (11);
- X# endif
- X *(r + i) = EOS;
- X return r;
- X}
- X
- X/*
- X Return the in-coming priority of an operator.
- X*/
- X
- Xint icp (int op)
- X{
- X if (op == OR || op == AND) return 1;
- X if (op == LPAREN || op == NOT) return 4;
- X return 0;
- X}
- X
- X/*
- X Push a new operand onto OPERAND_STACK.
- X*/
- X
- Xint push (int val)
- X{
- X OPERAND_STACK *s;
- X
- X if (! (s = (OPERAND_STACK *) malloc (sizeof (OPERAND_STACK))))
- X# ifndef test
- X report_progress (report, "\npush(): malloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "push(): malloc() failed\n"),
- X exit (11);
- X# endif
- X s->val = val;
- X s->prev = val_top;
- X s->next = NULL;
- X if (val_top)
- X val_top->next = s;
- X val_top = s;
- X return val;
- X}
- X
- X/*
- X Pop an operand from OPERAND_STACK. Return 0 or 1, or -1 on error.
- X*/
- X
- Xint pop ()
- X{
- X int val;
- X
- X if (!val_top) /* Empty stack */
- X return -1;
- X val = val_top->val;
- X if (val_top->prev)
- X val_top = val_top->prev,
- X free ((OPERAND_STACK *) val_top->next),
- X val_top->next = NULL;
- X else
- X free ((OPERAND_STACK *) val_top),
- X val_top = NULL;
- X return val;
- X}
- X
- X/*
- X Perform a boolean operation and return the result, or -1 on error.
- X*/
- X
- Xint do_op (int op, int val1, int val2)
- X{
- X if (val1 < 0 || val2 < 0)
- X return -1;
- X if (op == OR)
- X return val1 | val2;
- X if (op == AND)
- X return val1 & val2;
- X return !val1;
- X}
- X
- X/*
- X Pop an operator. An operator will always be present.
- X*/
- X
- Xvoid pop_op ()
- X{
- X OPERATOR_STACK *s;
- X
- X s = op_top;
- X op_top = op_top->prev;
- X if (op_top)
- X op_top->next = NULL;
- X free ((OPERATOR_STACK *) s);
- X}
- X
- X/*
- X Process a new operator: push it anyway, or push it after popping other
- X operators with higher priority. Return -1 on error condition.
- X*/
- X
- Xint new_op (int op)
- X{
- X OPERATOR_STACK *s;
- X int res;
- X
- X if (op < OR)
- X return -1;
- X if (op == RPAREN) {
- X do { /* Pop and process operators till LPAREN */
- X if (!op_top)
- X return -1;
- X if (op_top->op != LPAREN) {
- X if (op_top->op == OR || op_top->op == AND)
- X res = push (do_op (op_top->op, pop (), pop ()));
- X else /* NOT */
- X res = push (do_op (op_top->op, pop (), 0));
- X if (res < 0) /* Error with operands */
- X return res;
- X pop_op (); /* Pop processed operator */
- X if (!op_top)
- X return -1;
- X }
- X } while (op_top->op != LPAREN);
- X pop_op (); /* LPAREN */
- X }
- X else { /* Push new operator */
- X while (op_top && op_top->isp >= icp (op)) { /* Process op w/ > priority */
- X if (op_top->op == OR || op_top->op == AND)
- X res = push (do_op (op_top->op, pop (), pop ()));
- X else /* NOT */
- X res = push (do_op (op_top->op, pop (), 0));
- X if (res < 0)
- X return res;
- X pop_op ();
- X }
- X if (! (s = (OPERATOR_STACK *) malloc (sizeof (OPERATOR_STACK))))
- X# ifndef test
- X report_progress (report, "\nnew_op(): malloc() failed", 1),
- X exit (11);
- X# else
- X fprintf (stderr, "new_op(): malloc() failed\n"),
- X exit (11);
- X# endif
- X s->op = op;
- X if (op == OR) s->isp = 1;
- X else if (op == AND) s->isp = 1;
- X else if (op == NOT) s->isp = 2;
- X else s->isp = 0;
- X s->prev = op_top;
- X s->next = NULL;
- X if (op_top)
- X op_top->next = s;
- X op_top = s;
- X }
- X return 0;
- X}
- X
- X/*
- X Process the remaining operators and values. Return -1 on error.
- X*/
- X
- Xint eval ()
- X{
- X OPERATOR_STACK *op;
- X int res;
- X
- X if (!op_top && !val_top)
- X return 0;
- X while (op_top) {
- X if (op_top->op != AND && op_top->op != OR && op_top->op != NOT) {
- X if (op_top->op < OR || op_top->op > RPAREN)
- X# ifndef test
- X report_progress (report, "Internal error: unexpected op", 1);
- X# else
- X printf ("Internal error: unexpected op %d\n", op_top->op);
- X# endif
- X return -1;
- X }
- X if (op_top->op == OR || op_top->op == AND)
- X res = push (do_op (op_top->op, pop (), pop ()));
- X else /* NOT */
- X res = push (do_op (op_top->op, pop (), 0));
- X if (res < 0)
- X return res;
- X op = op_top;
- X op_top = op_top->prev;
- X free ((OPERATOR_STACK *) op);
- X }
- X if (!val_top) {
- X# ifndef test
- X report_progress (report, "Internal error: empty operand stack", 1);
- X# else
- X printf ("Internal error: empty operand stack\n");
- X# endif
- X return -1;
- X }
- X return pop ();
- X}
- X
- X/*
- X Return the operator id if indeed 's' points to an operator. Return -1
- X on error.
- X*/
- X
- Xint isop (char *s, char *b)
- X{
- X char pch, nch;
- X
- X pch = prevch (s, b);
- X if (literal) return 0;
- X nch = nextch (s);
- X if (*s == LGROUPCH)
- X if ((pch == '|' || pch == '&' || pch == '~' || pch == LGROUPCH) &&
- X !pliteral && ((nch != '|' && nch != '&' && nch != EOS) || nliteral))
- X return LPAREN;
- X else
- X return -1;
- X if (*s == RGROUPCH)
- X if (((pch != '|' && pch != '&' && pch != '~') || pliteral) && !nliteral &&
- X (nch == RGROUPCH || nch == '&' || nch == '|' || nch == EOS))
- X return RPAREN;
- X else
- X return -1;
- X if (*s == '~')
- X if ((pch == LGROUPCH || pch == '|' || pch == '&' || pch == '~') &&
- X !pliteral &&
- X ((nch != '|' && nch != '&' && nch != RGROUPCH && nch != EOS) ||
- X nliteral))
- X return NOT;
- X else
- X return -1;
- X if (*s == '|' || *s == '&')
- X if (((pch != '~' && pch != '|' && pch != '&') || pliteral) &&
- X ((nch != '|' && nch != '&' && nch != RGROUPCH &&
- X nch != EOS) || nliteral))
- X return (*s == '|' ? OR : AND);
- X else
- X return -1;
- X return 0;
- X}
- X#endif
- X
- X/*
- X Return the previous character from the current position in the
- X string. Set 'pliteral' to 1 if that previous character is escaped with \ and
- X 'literal' to 1 if the current character is escaped with \.
- X In the comments, ^ means "beginning of the string", ? matches any character
- X except \, * matches absolutely any character and x is the current position.
- X*/
- X
- Xint prevch (char *s, char *b)
- X{
- X return
- X ((s) <= (b) ?
- X (pliteral = literal = 0, *(s)) : /* ^x */
- X (((s) - 1) == (b) ?
- X (*((s) - 1) == '\\' ? (pliteral = !(literal = 1), *((s) - 1)) /* ^\x */
- X : (pliteral = literal = 0, *((s) - 1))) /* ^?x */
- X : (*(s) == '\\' ?
- X (*((s) - 2) == '\\' ? (pliteral = !(literal = 0), *((s) - 1)) /* \*\ */
- X : (*((s) - 1) == '\\' ? (pliteral = !(literal = 1), *((s) - 2)) /* ?\\ */
- X : (pliteral = literal = 0, *((s) - 1)))) /* ??\ */
- X : (*((s) - 1) == '\\' ?
- X (*((s) - 2) == '\\' ?
- X (((s) - 2) == (b) ? (pliteral = !(literal = 0), *((s) - 1)) /* ^\\x */
- X : (*((s) - 3) == '\\' ? (pliteral = literal = 1,*((s) - 2)) /* \\\x */
- X : (pliteral = !(literal = 0), *((s) - 1)))) /* ?\\x */
- X : (((s) - 2) == (b) ? (pliteral = !(literal = 1),*((s) - 2)) /* ^?\x */
- X : (*((s) - 3) == '\\' ? (pliteral = literal = 1, *((s) - 2)) /* \?\x */
- X : (pliteral = !(literal = 1), *((s) - 2))))) /* ??\x */
- X : (*((s) - 2) == '\\' ? (pliteral = !(literal = 0),*((s) - 1)) /* \?x */
- X : (pliteral = literal = 0, *((s) - 1))))))); /* ??x */
- X}
- X
- X/*
- X Return the next character from the current position. The current character
- X is guarranteed not to be a literal. In the comments below * matches
- X absolutely any character, ? matches anything but EOS, $ is the EOS and
- X x marks the current position. Also set 'nliteral' to 1 if the next character
- X is escaped with \.
- X*/
- X
- Xint nextch (char *s)
- X{
- X return
- X (*((s) + 1) == EOS ? (nliteral = 0, EOS) /* x$ */
- X : (*((s) + 1) == '\\' ?
- X (*((s) + 2) == EOS ? (nliteral = 0, *((s) + 1)) /* x\$ */
- X : (nliteral = 1, *((s) + 2))) /* x\? */
- X : (nliteral = 0, *((s) + 1)))); /* x* */
- X}
- X#ifdef test
- X
- X/*
- X Henry Spencer's code requires that $ be converted to .$
- X*/
- X
- Xvoid workaround (char *s)
- X{
- X char *r, *b = s;
- X
- X while (*s != EOS) {
- X switch (*s) {
- X case '$':
- X prevch (s, b); /* See if thi char is a literal */
- X if (literal) {
- X ++s;
- X continue;
- X }
- X r = s + strlen (s); /* Start from the end */
- X while (r != s)
- X *(r + 1) = *r,
- X --r;
- X *(r + 1) = *r;
- X *r = '.';
- X ++s;
- X break;
- X }
- X ++s;
- X }
- X}
- X#endif
- *-*-END-of-src/regex.c-*-*
- echo x - src/regexp.c
- sed 's/^X//' >src/regexp.c <<'*-*-END-of-src/regexp.c-*-*'
- X/*
- X * regcomp and regexec -- regsub and regerror are elsewhere
- X *
- X * Copyright (c) 1986 by University of Toronto.
- X * Written by Henry Spencer. Not derived from licensed software.
- X *
- X * Permission is granted to anyone to use this software for any
- X * purpose on any computer system, and to redistribute it freely,
- X * subject to the following restrictions:
- X *
- X * 1. The author is not responsible for the consequences of use of
- X * this software, no matter how awful, even if they arise
- X * from defects in it.
- X *
- X * 2. The origin of this software must not be misrepresented, either
- X * by explicit claim or by omission.
- X *
- X * 3. Altered versions must be plainly marked as such, and must not
- X * be misrepresented as being the original software.
- X *
- X * Beware that some of this code is subtly aware of the way operator
- X * precedence is structured in regular expressions. Serious changes in
- X * regular-expression syntax might require a total rethink.
- X */
- X#include <stdio.h>
- X#include "regexp.h"
- X#include "regmagic.h"
- X
- X/*
- X * The "internal use only" fields in regexp.h are present to pass info from
- X * compile to execute that permits the execute phase to run lots faster on
- X * simple cases. They are:
- X *
- X * regstart char that must begin a match; '\0' if none obvious
- X * reganch is the match anchored (at beginning-of-line only)?
- X * regmust string (pointer into program) that match must include, or NULL
- X * regmlen length of regmust string
- X *
- X * Regstart and reganch permit very fast decisions on suitable starting points
- X * for a match, cutting down the work a lot. Regmust permits fast rejection
- X * of lines that cannot possibly match. The regmust tests are costly enough
- X * that regcomp() supplies a regmust only if the r.e. contains something
- X * potentially expensive (at present, the only such thing detected is * or +
- X * at the start of the r.e., which can involve a lot of backup). Regmlen is
- X * supplied because the test in regexec() needs it and regcomp() is computing
- X * it anyway.
- X */
- X
- X/*
- X * Structure for regexp "program". This is essentially a linear encoding
- X * of a nondeterministic finite-state machine (aka syntax charts or
- X * "railroad normal form" in parsing technology). Each node is an opcode
- X * plus a "next" pointer, possibly plus an operand. "Next" pointers of
- X * all nodes except BRANCH implement concatenation; a "next" pointer with
- X * a BRANCH on both ends of it is connecting two alternatives. (Here we
- X * have one of the subtle syntax dependencies: an individual BRANCH (as
- X * opposed to a collection of them) is never concatenated with anything
- X * because of operator precedence.) The operand of some types of node is
- X * a literal string; for others, it is a node leading into a sub-FSM. In
- X * particular, the operand of a BRANCH node is the first node of the branch.
- X * (NB this is *not* a tree structure: the tail of the branch connects
- X * to the thing following the set of BRANCHes.) The opcodes are:
- X */
- X
- X/* definition number opnd? meaning */
- X#define END 0 /* no End of program. */
- X#define BOL 1 /* no Match "" at beginning of line. */
- X#define EOL 2 /* no Match "" at end of line. */
- X#define ANY 3 /* no Match any one character. */
- X#define ANYOF 4 /* str Match any character in this string. */
- X#define ANYBUT 5 /* str Match any character not in this string. */
- X#define BRANCH 6 /* node Match this alternative, or the next... */
- X#define BACK 7 /* no Match "", "next" ptr points backward. */
- X#define EXACTLY 8 /* str Match this string. */
- X#define NOTHING 9 /* no Match empty string. */
- X#define STAR 10 /* node Match this (simple) thing 0 or more times. */
- X#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
- X#define OPEN 20 /* no Mark this point in input as start of #n. */
- X /* OPEN+1 is number 1, etc. */
- X#define CLOSE 30 /* no Analogous to OPEN. */
- X
- X/*
- X * Opcode notes:
- X *
- X * BRANCH The set of branches constituting a single choice are hooked
- X * together with their "next" pointers, since precedence prevents
- X * anything being concatenated to any individual branch. The
- X * "next" pointer of the last BRANCH in a choice points to the
- X * thing following the whole choice. This is also where the
- X * final "next" pointer of each individual branch points; each
- X * branch starts with the operand node of a BRANCH node.
- X *
- X * BACK Normal "next" pointers all implicitly point forward; BACK
- X * exists to make loop structures possible.
- X *
- X * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
- X * BRANCH structures using BACK. Simple cases (one character
- X * per match) are implemented with STAR and PLUS for speed
- X * and to minimize recursive plunges.
- X *
- X * OPEN,CLOSE ...are numbered at compile time.
- X */
- X
- X/*
- X * A node is one char of opcode followed by two chars of "next" pointer.
- X * "Next" pointers are stored as two 8-bit pieces, high order first. The
- X * value is a positive offset from the opcode of the node containing it.
- X * An operand, if any, simply follows the node. (Note that much of the
- X * code generation knows about this implicit relationship.)
- X *
- X * Using two bytes for the "next" pointer is vast overkill for most things,
- X * but allows patterns to get big without disasters.
- X */
- X#define OP(p) (*(p))
- X#define NEXT(p) (((*((p)+1)&0377)<<8) + *((p)+2)&0377)
- X#define OPERAND(p) ((p) + 3)
- X
- X/*
- X * See regmagic.h for one further detail of program structure.
- X */
- X
- X
- X/*
- X * Utility definitions.
- X */
- X#ifndef CHARBITS
- X#define UCHARAT(p) ((int)*(unsigned char *)(p))
- X#else
- X#define UCHARAT(p) ((int)*(p)&CHARBITS)
- X#endif
- X
- X#define FAIL(m) { regerror(m); return(NULL); }
- X#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
- X#define META "^$.[()|?+*\\"
- X
- X/*
- X * Flags to be passed up and down.
- X */
- X#define HASWIDTH 01 /* Known never to match null string. */
- X#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
- X#define SPSTART 04 /* Starts with * or +. */
- X#define WORST 0 /* Worst case. */
- X
- X/*
- X * Global work variables for regcomp().
- X */
- Xstatic char *regparse; /* Input-scan pointer. */
- Xstatic int regnpar; /* () count. */
- Xstatic char regdummy;
- Xstatic char *regcode; /* Code-emit pointer; ®dummy = don't. */
- Xstatic long regsize; /* Code size. */
- X
- X/*
- X * Forward declarations for regcomp()'s friends.
- X */
- X#ifndef STATIC
- X#define STATIC static
- X#endif
- XSTATIC char *reg();
- XSTATIC char *regbranch();
- XSTATIC char *regpiece();
- XSTATIC char *regatom();
- XSTATIC char *regnode();
- XSTATIC char *regnext();
- XSTATIC void regc();
- XSTATIC void reginsert();
- XSTATIC void regtail();
- XSTATIC void regoptail();
- X#ifdef STRCSPN
- XSTATIC int strcspn();
- X#endif
- X
- X/*
- X - regcomp - compile a regular expression into internal code
- X *
- X * We can't allocate space until we know how big the compiled form will be,
- X * but we can't compile it (and thus know how big it is) until we've got a
- X * place to put the code. So we cheat: we compile it twice, once with code
- X * generation turned off and size counting turned on, and once "for real".
- X * This also means that we don't allocate space until we are sure that the
- X * thing really will compile successfully, and we never have to move the
- X * code and thus invalidate pointers into it. (Note that it has to be in
- X * one piece because free() must be able to free it all.)
- X *
- X * Beware that the optimization-preparation code in here knows about some
- X * of the structure of the compiled regexp.
- X */
- Xregexp *
- Xregcomp(exp)
- Xchar *exp;
- X{
- X register regexp *r;
- X register char *scan;
- X register char *longest;
- X register int len;
- X int flags;
- X extern char *malloc();
- X
- X if (exp == NULL)
- X FAIL("NULL argument");
- X
- X /* First pass: determine size, legality. */
- X regparse = exp;
- X regnpar = 1;
- X regsize = 0L;
- X regcode = ®dummy;
- X regc(MAGIC);
- X if (reg(0, &flags) == NULL)
- X return(NULL);
- X
- X /* Small enough for pointer-storage convention? */
- X if (regsize >= 32767L) /* Probably could be 65535L. */
- X FAIL("regexp too big");
- X
- X /* Allocate space. */
- X r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
- X if (r == NULL)
- X FAIL("out of space");
- X
- X /* Second pass: emit code. */
- X regparse = exp;
- X regnpar = 1;
- X regcode = r->program;
- X regc(MAGIC);
- X if (reg(0, &flags) == NULL)
- X return(NULL);
- X
- X /* Dig out information for optimizations. */
- X r->regstart = '\0'; /* Worst-case defaults. */
- X r->reganch = 0;
- X r->regmust = NULL;
- X r->regmlen = 0;
- X scan = r->program+1; /* First BRANCH. */
- X if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
- X scan = OPERAND(scan);
- X
- X /* Starting-point info. */
- X if (OP(scan) == EXACTLY)
- X r->regstart = *OPERAND(scan);
- X else if (OP(scan) == BOL)
- X r->reganch++;
- X
- X /*
- X * If there's something expensive in the r.e., find the
- X * longest literal string that must appear and make it the
- X * regmust. Resolve ties in favor of later strings, since
- X * the regstart check works with the beginning of the r.e.
- X * and avoiding duplication strengthens checking. Not a
- X * strong reason, but sufficient in the absence of others.
- X */
- X if (flags&SPSTART) {
- X longest = NULL;
- X len = 0;
- X for (; scan != NULL; scan = regnext(scan))
- X if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
- X longest = OPERAND(scan);
- X len = strlen(OPERAND(scan));
- X }
- X r->regmust = longest;
- X r->regmlen = len;
- X }
- X }
- X
- X return(r);
- X}
- X
- X/*
- X - reg - regular expression, i.e. main body or parenthesized thing
- X *
- X * Caller must absorb opening parenthesis.
- X *
- X * Combining parenthesis handling with the base level of regular expression
- X * is a trifle forced, but the need to tie the tails of the branches to what
- X * follows makes it hard to avoid.
- X */
- Xstatic char *
- Xreg(paren, flagp)
- Xint paren; /* Parenthesized? */
- Xint *flagp;
- X{
- X register char *ret;
- X register char *br;
- X register char *ender;
- X register int parno;
- X int flags;
- X
- X *flagp = HASWIDTH; /* Tentatively. */
- X
- X /* Make an OPEN node, if parenthesized. */
- X if (paren) {
- X if (regnpar >= NSUBEXP)
- X FAIL("too many ()");
- X parno = regnpar;
- X regnpar++;
- X ret = regnode(OPEN+parno);
- X } else
- X ret = NULL;
- X
- X /* Pick up the branches, linking them together. */
- X br = regbranch(&flags);
- X if (br == NULL)
- X return(NULL);
- X if (ret != NULL)
- X regtail(ret, br); /* OPEN -> first. */
- X else
- X ret = br;
- X if (!(flags&HASWIDTH))
- X *flagp &= ~HASWIDTH;
- X *flagp |= flags&SPSTART;
- X while (*regparse == '|') {
- X regparse++;
- X br = regbranch(&flags);
- X if (br == NULL)
- X return(NULL);
- X regtail(ret, br); /* BRANCH -> BRANCH. */
- X if (!(flags&HASWIDTH))
- X *flagp &= ~HASWIDTH;
- X *flagp |= flags&SPSTART;
- X }
- X
- X /* Make a closing node, and hook it on the end. */
- X ender = regnode((paren) ? CLOSE+parno : END);
- X regtail(ret, ender);
- X
- X /* Hook the tails of the branches to the closing node. */
- X for (br = ret; br != NULL; br = regnext(br))
- X regoptail(br, ender);
- X
- X /* Check for proper termination. */
- X if (paren && *regparse++ != ')') {
- X FAIL("unmatched ()");
- X } else if (!paren && *regparse != '\0') {
- X if (*regparse == ')') {
- X FAIL("unmatched ()");
- X } else
- X FAIL("junk on end"); /* "Can't happen". */
- X /* NOTREACHED */
- X }
- X
- X return(ret);
- X}
- X
- X/*
- X - regbranch - one alternative of an | operator
- X *
- X * Implements the concatenation operator.
- X */
- Xstatic char *
- Xregbranch(flagp)
- Xint *flagp;
- X{
- X register char *ret;
- X register char *chain;
- X register char *latest;
- X int flags;
- X
- X *flagp = WORST; /* Tentatively. */
- X
- X ret = regnode(BRANCH);
- X chain = NULL;
- X while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
- X latest = regpiece(&flags);
- X if (latest == NULL)
- X return(NULL);
- X *flagp |= flags&HASWIDTH;
- X if (chain == NULL) /* First piece. */
- X *flagp |= flags&SPSTART;
- X else
- X regtail(chain, latest);
- X chain = latest;
- X }
- X if (chain == NULL) /* Loop ran zero times. */
- X (void) regnode(NOTHING);
- X
- X return(ret);
- X}
- X
- X/*
- X - regpiece - something followed by possible [*+?]
- X *
- X * Note that the branching code sequences used for ? and the general cases
- X * of * and + are somewhat optimized: they use the same NOTHING node as
- X * both the endmarker for their branch list and the body of the last branch.
- X * It might seem that this node could be dispensed with entirely, but the
- X * endmarker role is not redundant.
- X */
- Xstatic char *
- Xregpiece(flagp)
- Xint *flagp;
- X{
- X register char *ret;
- X register char op;
- X register char *next;
- X int flags;
- X
- X ret = regatom(&flags);
- X if (ret == NULL)
- X return(NULL);
- X
- X op = *regparse;
- X if (!ISMULT(op)) {
- X *flagp = flags;
- X return(ret);
- X }
- X
- X if (!(flags&HASWIDTH) && op != '?')
- X FAIL("*+ operand could be empty");
- X *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
- X
- X if (op == '*' && (flags&SIMPLE))
- X reginsert(STAR, ret);
- X else if (op == '*') {
- X /* Emit x* as (x&|), where & means "self". */
- X reginsert(BRANCH, ret); /* Either x */
- X regoptail(ret, regnode(BACK)); /* and loop */
- X regoptail(ret, ret); /* back */
- X regtail(ret, regnode(BRANCH)); /* or */
- X regtail(ret, regnode(NOTHING)); /* null. */
- X } else if (op == '+' && (flags&SIMPLE))
- X reginsert(PLUS, ret);
- X else if (op == '+') {
- X /* Emit x+ as x(&|), where & means "self". */
- X next = regnode(BRANCH); /* Either */
- X regtail(ret, next);
- X regtail(regnode(BACK), ret); /* loop back */
- X regtail(next, regnode(BRANCH)); /* or */
- X regtail(ret, regnode(NOTHING)); /* null. */
- X } else if (op == '?') {
- X /* Emit x? as (x|) */
- X reginsert(BRANCH, ret); /* Either x */
- X regtail(ret, regnode(BRANCH)); /* or */
- X next = regnode(NOTHING); /* null. */
- X regtail(ret, next);
- X regoptail(ret, next);
- X }
- X regparse++;
- X if (ISMULT(*regparse))
- X FAIL("nested *?+");
- X
- X return(ret);
- X}
- X
- X/*
- X - regatom - the lowest level
- X *
- X * Optimization: gobbles an entire sequence of ordinary characters so that
- X * it can turn them into a single node, which is smaller to store and
- X * faster to run. Backslashed characters are exceptions, each becoming a
- X * separate node; the code is simpler that way and it's not worth fixing.
- X */
- Xstatic char *
- Xregatom(flagp)
- Xint *flagp;
- X{
- X register char *ret;
- X int flags;
- X
- X *flagp = WORST; /* Tentatively. */
- X
- X switch (*regparse++) {
- X case '^':
- X ret = regnode(BOL);
- X break;
- X case '$':
- X ret = regnode(EOL);
- X break;
- X case '.':
- X ret = regnode(ANY);
- X *flagp |= HASWIDTH|SIMPLE;
- X break;
- X case '[': {
- X register int class;
- X register int classend;
- X
- X if (*regparse == '^') { /* Complement of range. */
- X ret = regnode(ANYBUT);
- X regparse++;
- X } else
- X ret = regnode(ANYOF);
- X if (*regparse == ']' || *regparse == '-')
- X regc(*regparse++);
- X while (*regparse != '\0' && *regparse != ']') {
- X if (*regparse == '-') {
- X regparse++;
- X if (*regparse == ']' || *regparse == '\0')
- X regc('-');
- X else {
- X class = UCHARAT(regparse-2)+1;
- X classend = UCHARAT(regparse);
- X if (class > classend+1)
- X FAIL("invalid [] range");
- X for (; class <= classend; class++)
- X regc(class);
- X regparse++;
- X }
- X } else
- X regc(*regparse++);
- X }
- X regc('\0');
- X if (*regparse != ']')
- X FAIL("unmatched []");
- X regparse++;
- X *flagp |= HASWIDTH|SIMPLE;
- X }
- X break;
- X case '(':
- X ret = reg(1, &flags);
- X if (ret == NULL)
- X return(NULL);
- X *flagp |= flags&(HASWIDTH|SPSTART);
- X break;
- X case '\0':
- X case '|':
- X case ')':
- X FAIL("internal urp"); /* Supposed to be caught earlier. */
- X break;
- X case '?':
- X case '+':
- X case '*':
- X FAIL("?+* follows nothing");
- X break;
- X case '\\':
- X if (*regparse == '\0')
- X FAIL("trailing \\");
- X ret = regnode(EXACTLY);
- X regc(*regparse++);
- X regc('\0');
- X *flagp |= HASWIDTH|SIMPLE;
- X break;
- X default: {
- X register int len;
- X register char ender;
- X
- X regparse--;
- X len = strcspn(regparse, META);
- X if (len <= 0)
- X FAIL("internal disaster");
- X ender = *(regparse+len);
- X if (len > 1 && ISMULT(ender))
- X len--; /* Back off clear of ?+* operand. */
- X *flagp |= HASWIDTH;
- X if (len == 1)
- X *flagp |= SIMPLE;
- X ret = regnode(EXACTLY);
- X while (len > 0) {
- X regc(*regparse++);
- X len--;
- X }
- X regc('\0');
- X }
- X break;
- X }
- X
- X return(ret);
- X}
- X
- X/*
- X - regnode - emit a node
- X */
- Xstatic char * /* Location. */
- Xregnode(op)
- Xchar op;
- X{
- X register char *ret;
- X register char *ptr;
- X
- X ret = regcode;
- X if (ret == ®dummy) {
- X regsize += 3;
- X return(ret);
- X }
- X
- X ptr = ret;
- X *ptr++ = op;
- X *ptr++ = '\0'; /* Null "next" pointer. */
- X *ptr++ = '\0';
- X regcode = ptr;
- X
- X return(ret);
- X}
- X
- X/*
- X - regc - emit (if appropriate) a byte of code
- X */
- Xstatic void
- Xregc(b)
- Xchar b;
- X{
- X if (regcode != ®dummy)
- X *regcode++ = b;
- X else
- X regsize++;
- X}
- X
- X/*
- X - reginsert - insert an operator in front of already-emitted operand
- X *
- X * Means relocating the operand.
- X */
- Xstatic void
- Xreginsert(op, opnd)
- Xchar op;
- Xchar *opnd;
- X{
- X register char *src;
- X register char *dst;
- X register char *place;
- X
- X if (regcode == ®dummy) {
- X regsize += 3;
- X return;
- X }
- X
- X src = regcode;
- X regcode += 3;
- X dst = regcode;
- X while (src > opnd)
- X *--dst = *--src;
- X
- X place = opnd; /* Op node, where operand used to be. */
- X *place++ = op;
- X *place++ = '\0';
- X *place++ = '\0';
- X}
- X
- X/*
- X - regtail - set the next-pointer at the end of a node chain
- X */
- Xstatic void
- Xregtail(p, val)
- Xchar *p;
- Xchar *val;
- X{
- X register char *scan;
- X register char *temp;
- X register int offset;
- X
- X if (p == ®dummy)
- X return;
- X
- X /* Find last node. */
- X scan = p;
- X for (;;) {
- X temp = regnext(scan);
- X if (temp == NULL)
- X break;
- X scan = temp;
- X }
- X
- X if (OP(scan) == BACK)
- X offset = scan - val;
- X else
- X offset = val - scan;
- X *(scan+1) = (offset>>8)&0377;
- X *(scan+2) = offset&0377;
- X}
- X
- X/*
- X - regoptail - regtail on operand of first argument; nop if operandless
- X */
- Xstatic void
- Xregoptail(p, val)
- Xchar *p;
- Xchar *val;
- X{
- X /* "Operandless" and "op != BRANCH" are synonymous in practice. */
- X if (p == NULL || p == ®dummy || OP(p) != BRANCH)
- X return;
- X regtail(OPERAND(p), val);
- X}
- X
- X/*
- X * regexec and friends
- X */
- X
- X/*
- X * Global work variables for regexec().
- X */
- Xstatic char *reginput; /* String-input pointer. */
- Xstatic char *regbol; /* Beginning of input, for ^ check. */
- Xstatic char **regstartp; /* Pointer to startp array. */
- Xstatic char **regendp; /* Ditto for endp. */
- X
- X/*
- X * Forwards.
- X */
- XSTATIC int regtry();
- XSTATIC int regmatch();
- XSTATIC int regrepeat();
- X
- X#ifdef DEBUG
- Xint regnarrate = 0;
- Xvoid regdump();
- XSTATIC char *regprop();
- X#endif
- X
- X/*
- X - regexec - match a regexp against a string
- X */
- Xint
- Xregexec(prog, string)
- Xregister regexp *prog;
- Xregister char *string;
- X{
- X register char *s;
- X extern char *strchr();
- X
- X /* Be paranoid... */
- X if (prog == NULL || string == NULL) {
- X regerror("NULL parameter");
- X return(0);
- X }
- X
- X /* Check validity of program. */
- X if (UCHARAT(prog->program) != MAGIC) {
- X regerror("corrupted program");
- X return(0);
- X }
- X
- X /* If there is a "must appear" string, look for it. */
- X if (prog->regmust != NULL) {
- X s = string;
- X while ((s = strchr(s, prog->regmust[0])) != NULL) {
- X if (strncmp(s, prog->regmust, prog->regmlen) == 0)
- X break; /* Found it. */
- X s++;
- X }
- X if (s == NULL) /* Not present. */
- X return(0);
- X }
- X
- X /* Mark beginning of line for ^ . */
- X regbol = string;
- X
- X /* Simplest case: anchored match need be tried only once. */
- X if (prog->reganch)
- X return(regtry(prog, string));
- X
- X /* Messy cases: unanchored match. */
- X s = string;
- X if (prog->regstart != '\0')
- X /* We know what char it must start with. */
- X while ((s = strchr(s, prog->regstart)) != NULL) {
- X if (regtry(prog, s))
- X return(1);
- X s++;
- X }
- X else
- X /* We don't -- general case. */
- X do {
- X if (regtry(prog, s))
- X return(1);
- X } while (*s++ != '\0');
- X
- X /* Failure. */
- X return(0);
- X}
- X
- X/*
- X - regtry - try match at specific point
- X */
- Xstatic int /* 0 failure, 1 success */
- Xregtry(prog, string)
- Xregexp *prog;
- Xchar *string;
- X{
- X register int i;
- X register char **sp;
- X register char **ep;
- X
- X reginput = string;
- X regstartp = prog->startp;
- X regendp = prog->endp;
- X
- X sp = prog->startp;
- X ep = prog->endp;
- X for (i = NSUBEXP; i > 0; i--) {
- X *sp++ = NULL;
- X *ep++ = NULL;
- X }
- X if (regmatch(prog->program + 1)) {
- X prog->startp[0] = string;
- X prog->endp[0] = reginput;
- X return(1);
- X } else
- X return(0);
- X}
- X
- X/*
- X - regmatch - main matching routine
- X *
- X * Conceptually the strategy is simple: check to see whether the current
- X * node matches, call self recursively to see whether the rest matches,
- X * and then act accordingly. In practice we make some effort to avoid
- X * recursion, in particular by going through "ordinary" nodes (that don't
- X * need to know whether the rest of the match failed) by a loop instead of
- X * by recursion.
- X */
- Xstatic int /* 0 failure, 1 success */
- Xregmatch(prog)
- Xchar *prog;
- X{
- X register char *scan; /* Current node. */
- X char *next; /* Next node. */
- X extern char *strchr();
- X
- X scan = prog;
- X#ifdef DEBUG
- X if (scan != NULL && regnarrate)
- X fprintf(stderr, "%s(\n", regprop(scan));
- X#endif
- X while (scan != NULL) {
- X#ifdef DEBUG
- X if (regnarrate)
- X fprintf(stderr, "%s...\n", regprop(scan));
- X#endif
- X next = regnext(scan);
- X
- X switch (OP(scan)) {
- X case BOL:
- X if (reginput != regbol)
- X return(0);
- X break;
- X case EOL:
- X if (*reginput != '\0')
- X return(0);
- X break;
- X case ANY:
- X if (*reginput == '\0')
- X return(0);
- X reginput++;
- X break;
- X case EXACTLY: {
- X register int len;
- X register char *opnd;
- X
- X opnd = OPERAND(scan);
- X /* Inline the first character, for speed. */
- X if (*opnd != *reginput)
- X return(0);
- X len = strlen(opnd);
- X if (len > 1 && strncmp(opnd, reginput, len) != 0)
- X return(0);
- X reginput += len;
- X }
- X break;
- X case ANYOF:
- X if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
- X return(0);
- X reginput++;
- X break;
- X case ANYBUT:
- X if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
- X return(0);
- X reginput++;
- X break;
- X case NOTHING:
- X break;
- X case BACK:
- X break;
- X case OPEN+1:
- X case OPEN+2:
- X case OPEN+3:
- X case OPEN+4:
- X case OPEN+5:
- X case OPEN+6:
- X case OPEN+7:
- X case OPEN+8:
- X case OPEN+9: {
- X register int no;
- X register char *save;
- X
- X no = OP(scan) - OPEN;
- X save = reginput;
- X
- X if (regmatch(next)) {
- X /*
- X * Don't set startp if some later
- X * invocation of the same parentheses
- X * already has.
- X */
- X if (regstartp[no] == NULL)
- X regstartp[no] = save;
- X return(1);
- X } else
- X return(0);
- X }
- X break;
- X case CLOSE+1:
- X case CLOSE+2:
- X case CLOSE+3:
- X case CLOSE+4:
- X case CLOSE+5:
- X case CLOSE+6:
- X case CLOSE+7:
- X case CLOSE+8:
- X case CLOSE+9: {
- X register int no;
- X register char *save;
- X
- X no = OP(scan) - CLOSE;
- X save = reginput;
- X
- X if (regmatch(next)) {
- X /*
- X * Don't set endp if some later
- X * invocation of the same parentheses
- X * already has.
- X */
- X if (regendp[no] == NULL)
- X regendp[no] = save;
- X return(1);
- X } else
- X return(0);
- X }
- X break;
- X case BRANCH: {
- X register char *save;
- X
- X if (OP(next) != BRANCH) /* No choice. */
- X next = OPERAND(scan); /* Avoid recursion. */
- X else {
- X do {
- X save = reginput;
- X if (regmatch(OPERAND(scan)))
- X return(1);
- X reginput = save;
- X scan = regnext(scan);
- X } while (scan != NULL && OP(scan) == BRANCH);
- X return(0);
- X /* NOTREACHED */
- X }
- X }
- X break;
- X case STAR:
- X case PLUS: {
- X register char nextch;
- X register int no;
- X register char *save;
- X register int min;
- X
- X /*
- X * Lookahead to avoid useless match attempts
- X * when we know what character comes next.
- X */
- X nextch = '\0';
- X if (OP(next) == EXACTLY)
- X nextch = *OPERAND(next);
- X min = (OP(scan) == STAR) ? 0 : 1;
- X save = reginput;
- X no = regrepeat(OPERAND(scan));
- X while (no >= min) {
- X /* If it could work, try it. */
- X if (nextch == '\0' || *reginput == nextch)
- X if (regmatch(next))
- X return(1);
- X /* Couldn't or didn't -- back up. */
- X no--;
- X reginput = save + no;
- X }
- X return(0);
- X }
- X break;
- X case END:
- X return(1); /* Success! */
- X break;
- X default:
- X regerror("memory corruption");
- X return(0);
- X break;
- X }
- X
- X scan = next;
- X }
- X
- X /*
- X * We get here only if there's trouble -- normally "case END" is
- X * the terminating point.
- X */
- X regerror("corrupted pointers");
- X return(0);
- X}
- X
- X/*
- X - regrepeat - repeatedly match something simple, report how many
- X */
- Xstatic int
- Xregrepeat(p)
- Xchar *p;
- X{
- X register int count = 0;
- X register char *scan;
- X register char *opnd;
- X extern char *strchr();
- X
- X scan = reginput;
- X opnd = OPERAND(p);
- X switch (OP(p)) {
- X case ANY:
- X count = strlen(scan);
- X scan += count;
- X break;
- X case EXACTLY:
- X while (*opnd == *scan) {
- X count++;
- X scan++;
- X }
- X break;
- X case ANYOF:
- X while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
- X count++;
- X scan++;
- X }
- X break;
- X case ANYBUT:
- X while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
- X count++;
- X scan++;
- X }
- X break;
- X default: /* Oh dear. Called inappropriately. */
- X regerror("internal foulup");
- X count = 0; /* Best compromise. */
- X break;
- X }
- X reginput = scan;
- X
- X return(count);
- X}
- X
- X/*
- X - regnext - dig the "next" pointer out of a node
- X */
- Xstatic char *
- Xregnext(p)
- Xregister char *p;
- X{
- X register int offset;
- X
- X if (p == ®dummy)
- X return(NULL);
- X
- X offset = NEXT(p);
- X if (offset == 0)
- X return(NULL);
- X
- X if (OP(p) == BACK)
- X return(p-offset);
- X else
- X return(p+offset);
- X}
- X
- X#ifdef DEBUG
- X
- XSTATIC char *regprop();
- X
- X/*
- X - regdump - dump a regexp onto stdout in vaguely comprehensible form
- X */
- Xvoid
- Xregdump(r)
- Xregexp *r;
- X{
- X register char *s;
- X register char op = EXACTLY; /* Arbitrary non-END op. */
- X register char *next;
- X extern char *strchr();
- X
- X
- X s = r->program + 1;
- X while (op != END) { /* While that wasn't END last time... */
- X op = OP(s);
- X printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
- X next = regnext(s);
- X if (next == NULL) /* Next ptr. */
- X printf("(0)");
- X else
- X printf("(%d)", (s-r->program)+(next-s));
- X s += 3;
- X if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
- X /* Literal string, where present. */
- X while (*s != '\0') {
- X putchar(*s);
- X s++;
- X }
- X s++;
- X }
- X putchar('\n');
- X }
- X
- X /* Header fields of interest. */
- X if (r->regstart != '\0')
- X printf("start `%c' ", r->regstart);
- X if (r->reganch)
- X printf("anchored ");
- X if (r->regmust != NULL)
- X printf("must have \"%s\"", r->regmust);
- X printf("\n");
- X}
- X
- X/*
- X - regprop - printable representation of opcode
- X */
- Xstatic char *
- Xregprop(op)
- Xchar *op;
- X{
- X register char *p;
- X static char buf[50];
- X
- X (void) strcpy(buf, ":");
- X
- X switch (OP(op)) {
- X case BOL:
- X p = "BOL";
- X break;
- X case EOL:
- X p = "EOL";
- X break;
- X case ANY:
- X p = "ANY";
- X break;
- X case ANYOF:
- X p = "ANYOF";
- X break;
- X case ANYBUT:
- X p = "ANYBUT";
- X break;
- X case BRANCH:
- X p = "BRANCH";
- X break;
- X case EXACTLY:
- X p = "EXACTLY";
- X break;
- X case NOTHING:
- X p = "NOTHING";
- X break;
- X case BACK:
- X p = "BACK";
- X break;
- X case END:
- X p = "END";
- X break;
- X case OPEN+1:
- X case OPEN+2:
- X case OPEN+3:
- X case OPEN+4:
- X case OPEN+5:
- X case OPEN+6:
- X case OPEN+7:
- X case OPEN+8:
- X case OPEN+9:
- X sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
- X p = NULL;
- X break;
- X case CLOSE+1:
- X case CLOSE+2:
- X case CLOSE+3:
- X case CLOSE+4:
- X case CLOSE+5:
- X case CLOSE+6:
- X case CLOSE+7:
- X case CLOSE+8:
- X case CLOSE+9:
- X sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
- X p = NULL;
- X break;
- X case STAR:
- X p = "STAR";
- X break;
- X case PLUS:
- X p = "PLUS";
- X break;
- X default:
- X regerror("corrupted opcode");
- X break;
- X }
- X if (p != NULL)
- X (void) strcat(buf, p);
- X return(buf);
- X}
- X#endif
- X
- X/*
- X * The following is provided for those people who do not have strcspn() in
- X * their C libraries. They should get off their butts and do something
- X * about it; at least one public-domain implementation of those (highly
- X * useful) string routines has been published on Usenet.
- X */
- X#ifdef STRCSPN
- X/*
- X * strcspn - find length of initial segment of s1 consisting entirely
- X * of characters not from s2
- X */
- X
- Xstatic int
- Xstrcspn(s1, s2)
- Xchar *s1;
- Xchar *s2;
- X{
- X register char *scan1;
- X register char *scan2;
- X register int count;
- X
- X count = 0;
- X for (scan1 = s1; *scan1 != '\0'; scan1++) {
- X for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
- X if (*scan1 == *scan2++)
- X return(count);
- X count++;
- X }
- X return(count);
- X}
- X#endif
- *-*-END-of-src/regexp.c-*-*
- echo x - src/regsub.c
- sed 's/^X//' >src/regsub.c <<'*-*-END-of-src/regsub.c-*-*'
- X/*
- X * regsub
- X *
- X * Copyright (c) 1986 by University of Toronto.
- X * Written by Henry Spencer. Not derived from licensed software.
- X *
- X * Permission is granted to anyone to use this software for any
- X * purpose on any computer system, and to redistribute it freely,
- X * subject to the following restrictions:
- X *
- X * 1. The author is not responsible for the consequences of use of
- X * this software, no matter how awful, even if they arise
- X * from defects in it.
- X *
- X * 2. The origin of this software must not be misrepresented, either
- X * by explicit claim or by omission.
- X *
- X * 3. Altered versions must be plainly marked as such, and must not
- X * be misrepresented as being the original software.
- X */
- X#include <stdio.h>
- X#include "regexp.h"
- X#include "regmagic.h"
- X
- X#ifndef CHARBITS
- X#define UCHARAT(p) ((int)*(unsigned char *)(p))
- X#else
- X#define UCHARAT(p) ((int)*(p)&CHARBITS)
- X#endif
- X
- X/*
- X - regsub - perform substitutions after a regexp match
- X */
- Xvoid
- Xregsub(prog, source, dest)
- Xregexp *prog;
- Xchar *source;
- Xchar *dest;
- X{
- X register char *src;
- X register char *dst;
- X register char c;
- X register int no;
- X register int len;
- X extern char *strncpy();
- X
- X if (prog == NULL || source == NULL || dest == NULL) {
- X regerror("NULL parm to regsub");
- X return;
- X }
- X if (UCHARAT(prog->program) != MAGIC) {
- X regerror("damaged regexp fed to regsub");
- X return;
- X }
- X
- X src = source;
- X dst = dest;
- X while ((c = *src++) != '\0') {
- X if (c == '&')
- X no = 0;
- X else if (c == '\\' && '0' <= *src && *src <= '9')
- X no = *src++ - '0';
- X else
- X no = -1;
- X
- X if (no < 0) { /* Ordinary character. */
- X if (c == '\\' && (*src == '\\' || *src == '&'))
- X c = *src++;
- X *dst++ = c;
- X }
- X else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
- X len = prog->endp[no] - prog->startp[no];
- X (void) strncpy(dst, prog->startp[no], len);
- X dst += len;
- X if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
- X regerror("damaged match string");
- X return;
- X }
- X }
- X }
- X *dst++ = '\0';
- X}
- *-*-END-of-src/regsub.c-*-*
- echo x - src/rev.c
- sed 's/^X//' >src/rev.c <<'*-*-END-of-src/rev.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | REVERSE ORDER OF INPUT |
- X | |
- X | Version 1.0 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X*/
- X
- X#include <stdio.h>
- X
- Xmain ()
- X{
- X char linein[65536];
- X char lineout[65536];
- X long int i, j;
- X
- X while (!feof (stdin)) {
- X linein[0] = lineout[0] = '\0';
- X fgets (linein, 65535, stdin);
- X j = strlen (linein);
- X if (j && linein [j - 1] == '\n')
- X lineout [j - 1]= '\n',
- X --j;
- X for (i = j - 1, j = 0; i >= 0; i--)
- X lineout[j++] = linein[i];
- X if (lineout[j] == '\n') j++;
- X lineout[j] = '\0';
- X fputs (lineout, stdout);
- X }
- X exit (0);
- X}
- *-*-END-of-src/rev.c-*-*
- echo x - src/sem.c
- sed 's/^X//' >src/sem.c <<'*-*-END-of-src/sem.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | SEMAPHORE OPERATIONS |
- X | |
- X | version 1.0 |
- X | |
- X | User contributed code. |
- X | Author: Thimios Panagos <thimios@cs.bu.edu> |
- X ----------------------------------------------------------------------------
- X*/
- X
- X#include <signal.h>
- X#include "defs.h"
- X#ifdef GO_INTERACTIVE
- X# include <stdio.h>
- X# include <sys/types.h>
- X# include <sys/ipc.h>
- X# include <sys/sem.h>
- X
- Xint semtran (int);
- Xint semcall (int, int);
- Xint P (int, int);
- Xint V (int, int);
- Xvoid semremove (int);
- X
- X/*
- X Create a semaphore. Return the semaphore id, or -1 on error.
- X*/
- X
- Xint semtran (int key)
- X{
- X int sid;
- X
- X if ((sid = semget ((key_t) key, 1, 0600 | IPC_CREAT | SEM_UNDO)) < 0)
- X return -1;
- X return sid;
- X}
- X
- X/*
- X Operate on a semaphore (increment or decrement).
- X*/
- X
- Xint semcall (int sid, int op)
- X{
- X struct sembuf sb;
- X
- X sb.sem_num = sb.sem_flg = 0;
- X sb.sem_op = op;
- X
- X if (semop (sid, &sb, 1) == -1)
- X return -1;
- X return 0;
- X}
- X
- X/*
- X P semaphore; call when attempting to get into critical section.
- X*/
- X
- Xint P (int sid, int op)
- X{
- X if (semcall (sid, op))
- X return -1;
- X return 0;
- X}
- X
- X/*
- X V semaphore; call when out of critical section.
- X*/
- X
- Xint V (int sid, int op)
- X{
- X if (semcall (sid, -op))
- X return -1;
- X return 0;
- X}
- X
- X/*
- X Destroy a semaphore.
- X*/
- X
- Xvoid semremove (int sid)
- X{
- X (void) semctl (sid, 0, IPC_RMID, 0);
- X}
- X#endif
- *-*-END-of-src/sem.c-*-*
- echo x - src/semset.c
- sed 's/^X//' >src/semset.c <<'*-*-END-of-src/semset.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | Semaphore manipulation UTILITY |
- X | |
- X | Version 1.0 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X Use this utility to check and reset (if necessary) the concurrency control
- X of the system. If some process seems "stuck", use semset with the semaphore
- X id to determine what it is doing. To reset use a value of zero:
- X
- X % semset
- X
- X will invoke ipcs -s and show you all current semapahores.
- X
- X % semset semid
- X
- X will show you the current value and flags for the particular semaphore.
- X
- X $ semset semid value
- X
- X will show the current value and flags, then reset its value to the desired
- X one.
- X*/
- X
- X#include <stdio.h>
- X#include <signal.h>
- X#include "defs.h"
- X
- X#ifdef GO_INTERACTIVE
- X# include <sys/types.h>
- X# include <sys/ipc.h>
- X# include <sys/sem.h>
- X
- Xmain (int argc, char **argv)
- X{
- X union semun {
- X int val;
- X struct semid_ds *buf;
- X ushort *array;
- X } sem;
- X
- X if (argc < 2)
- X system ("ipcs -sa"),
- X exit (0);
- X if (!strcmp (argv [1], "-u"))
- X fprintf (stderr, "Usage: %s [semaphore id [new value]]\n", argv [0]),
- X exit (3);
- X if ((sem.val = semctl (atoi (argv [1]), 0, GETVAL, 0)) < 0)
- X perror ("semctl()"),
- X exit (1);
- X printf ("Current value: 0x%x", sem.val);
- X eval (sem.val);
- X printf ("\n");
- X if (argc >= 3) {
- X sem.val = atoi (argv[2]);
- X if (semctl (atoi (argv [1]), 0, SETVAL, sem))
- X perror ("semctl()"),
- X exit (1);
- X printf ("New value: 0x%x", sem.val);
- X eval (sem.val);
- X printf ("\n");
- X }
- X exit (0);
- X}
- X
- Xeval (int val)
- X{
- X if (val) {
- X printf ("; flags on:");
- X if (val & SEM_REQ_ID)
- X printf (" SEM_REQ_ID");
- X if (val & SEM_SYSFILES)
- X printf (" SEM_SYSFILES");
- X if (val & SEM_LISTFILES)
- X printf (" SEM_LISTFILES");
- X if (val & SEM_ARCHIVES)
- X printf (" SEM_ARCHIVES");
- X if (val & SEM_DLVR_MAIL)
- X printf (" SEM_DLVR_MAIL");
- X }
- X}
- X#else
- Xmain ()
- X{
- X printf ("The system does not go live.\n");
- X exit (0);
- X}
- X#endif
- *-*-END-of-src/semset.c-*-*
- echo x - src/sender.c
- sed 's/^X//' >src/sender.c <<'*-*-END-of-src/sender.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | SENDER ORIENTED FUNCTIONS |
- X | |
- X | Version 2.4 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X*/
- X
- X#include <stdio.h>
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <string.h>
- X#include <ctype.h>
- X#include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X#include <signal.h>
- X#include "defs.h"
- X
- X#ifdef GO_INTERACTIVE
- Xextern int sid;
- X# include <sys/types.h>
- X# include <sys/ipc.h>
- X# include <sys/sem.h>
- X# ifndef SYSLOG
- X# define IN_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0) {\
- X int val;\
- X while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
- X if (P (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error P(); errno %d",\
- X __func__, errno), TRUE),\
- X fclose (report),\
- X exit (14);\
- X }
- X# else
- X# define IN_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0) {\
- X int val;\
- X while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
- X if (P (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error P(); errno %d",\
- X __func__, errno), TRUE),\
- X exit (14);\
- X }
- X# endif
- X
- X# ifndef SYSLOG
- X# define OUT_OF_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0)\
- X if (V (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error V(); errno %d",\
- X __func__, errno), TRUE),\
- X fclose (report),\
- X exit (14);
- X# else
- X# define OUT_OF_CRITICAL_SECTION(__func__, mask)\
- X if (sid >= 0)\
- X if (V (sid, (mask)) < 0)\
- X report_progress (report, tsprintf ("\n%s(): Error V(); errno %d",\
- X __func__, errno), TRUE),\
- X exit (14);
- X# endif
- X#endif
- X
- X#define _SUBSCRIBERS 1
- X#define _ALIASES 2
- X#define OTHER 3
- X
- Xextern FILE *report;
- X
- X#ifdef __STDC__
- Xextern char *tsprintf (char *, ...);
- X#else
- Xextern char *tsprintf ();
- X#endif
- Xextern char **alternate_addresses;
- X
- Xextern void report_progress (FILE *, char *, int);
- Xextern char *upcase (char *);
- Xextern int gexit (int);
- Xextern int re_strcmp (char *, char *, char *);
- Xextern int P (int, int);
- Xextern int V (int, int);
- Xextern char *mystrdup (char *);
- X
- XBOOLEAN subscribed (FILE *, char *, char *, char *, char *, char *, BOOLEAN);
- XBOOLEAN check_file (FILE *, char *, char *, BOOLEAN);
- XBOOLEAN ignore_sender (FILE *, char *, FILE *, BOOLEAN);
- XBOOLEAN owner_listed (char *, char *, char *, FILE *);
- XBOOLEAN host_listed (char *, char *, FILE *);
- Xvoid check_aliases (char *, char *);
- XBOOLEAN extract_sender (char *);
- XBOOLEAN extract_subscriber (FILE *, char *, BOOLEAN);
- Xvoid extract_origin (char *);
- Xvoid extract_address (char *);
- Xvoid escape_address (char *);
- X
- X/*
- X Check if 'sender' is subscribed. Return SUBSCRIBED, NEWS, PEER or
- X NOTSUBSCRIBED. Comparisons are done in upper case.
- X*/
- X
- XBOOLEAN subscribed (FILE *report, char *sender, char *Subscribersf,
- X char *Newsf, char *Peersf, char *Aliasesf,
- X BOOLEAN block_sem)
- X{
- X int code;
- X if (!Subscribersf) /* call made by distribute () in listproc.c */
- X return NOTSUBSCRIBED;
- X#ifdef GO_INTERACTIVE
- X if (block_sem) {
- X IN_CRITICAL_SECTION ("subscribed", SEM_LISTFILES);
- X }
- X#endif
- X alternate_addresses = NULL;
- X if (check_file (report, sender, Subscribersf, _SUBSCRIBERS) ||
- X (check_file (report, sender, Aliasesf, _ALIASES) &&
- X check_file (report, sender, Subscribersf, _SUBSCRIBERS)))
- X code = SUBSCRIBED;
- X else if (Newsf &&
- X (check_file (report, sender, Newsf, OTHER) ||
- X (check_file (report, sender, Aliasesf, _ALIASES) &&
- X check_file (report, sender, Newsf, OTHER))))
- X code = NEWS;
- X else if (Peersf &&
- X (check_file (report, sender, Peersf, OTHER) ||
- X (check_file (report, sender, Aliasesf, _ALIASES) &&
- X check_file (report, sender, Peersf, OTHER))))
- X code = PEER;
- X else
- X code = NOTSUBSCRIBED;
- X#ifdef GO_INTERACTIVE
- X if (block_sem) {
- X OUT_OF_CRITICAL_SECTION ("subscribed", SEM_LISTFILES);
- X }
- X#endif
- X return code;
- X}
- X
- X/*
- X Check the given file for subscription. If the file is an aliases file
- X and the sender is listed in there, store his actual mailing address
- X in 'sender'.
- X*/
- X
- XBOOLEAN check_file (FILE *report, char *sender, char *file,
- X BOOLEAN which_file)
- X{
- X char subscriber [MAX_LINE];
- X char sender_copy [MAX_LINE];
- X char mode [MAX_LINE];
- X char othermode [MAX_LINE];
- X char name [MAX_LINE];
- X char *at, *dot, *s;
- X FILE *f;
- X int i, nmatches = 0;
- X extern char password_in_sub_file [];
- X
- X if (file == NULL || *sender == EOS) /* serverd does not check the aliases files */
- X return NOTSUBSCRIBED;
- X OPEN_FILE (f, file, "r", "check_file");
- X upcase (sender); /* Convert to upper case */
- X while (!feof (f)) { /* Check list of subscribers/peers/news/aliases */
- X subscriber[0] = mode[0] = othermode[0] = RESET (name);
- X extract_subscriber (f, subscriber, (which_file == _ALIASES ? TRUE : FALSE));
- X if (subscriber[0] != EOS) {
- X fscanf (f, "%s ", mode);
- X if (which_file == _SUBSCRIBERS) /* Only this file may have more options */
- X for (i = 1; i < MAX_SET_OPTIONS - 1; i++) {
- X fscanf (f, "%s ", othermode);
- X if (i == 1) /* Save user's password */
- X strcpy (password_in_sub_file, othermode);
- X }
- X if (which_file != _ALIASES)
- X fgets (name, MAX_LINE - 2, f);
- X upcase (subscriber);
- X if ((which_file == _ALIASES && re_strcmp (subscriber, sender, mode) > 0)
- X || (which_file != _ALIASES && !strcmp (subscriber, sender))) {
- X fclose (f);
- X if (which_file == _ALIASES)
- X upcase (mode),
- X strcpy (sender, mode); /* Note: mode now is address-as-subscribed */
- X return SUBSCRIBED;
- X }
- X strcpy (sender_copy, sender);
- X if ((at = strchr (sender_copy, '@')) && (dot = strchr (at, '.')) &&
- X at != dot + 1) {
- X sprintf (at + 1, ".*%s", (s = mystrdup (dot + 1)));
- X free ((char *) s);
- X if (re_strcmp (sender_copy, subscriber, NULL) > 0) {
- X if (!alternate_addresses) {
- X if ((alternate_addresses = (char **) malloc (2 * sizeof (char *)))
- X == NULL)
- X report_progress (report, "\ncheck_file(): malloc() failed", TRUE),
- X gexit (11);
- X }
- X else
- X if ((alternate_addresses = (char **)
- X realloc ((char **) alternate_addresses,
- X sizeof (char *) * (nmatches + 2))) == NULL)
- X report_progress (report, "\ncheck_file(): realloc() failed", TRUE),
- X gexit (11);
- X alternate_addresses [nmatches + 1] = NULL;
- X alternate_addresses [nmatches] = (char *)
- X malloc ((strlen (subscriber) + 1) * sizeof (char));
- X strcpy (alternate_addresses [nmatches++], subscriber);
- X }
- X }
- X }
- X }
- X fclose (f);
- X return NOTSUBSCRIBED;
- X}
- X
- X/*
- X Check if 'sender' appears in the IGNORED file or MESSAGE_IDS.
- X*/
- X
- XBOOLEAN ignore_sender (FILE *ignored, char *sender, FILE *report,
- X BOOLEAN literal_match)
- X{
- X char ignored_user [MAX_LINE];
- X char line[MAX_LINE];
- X
- X rewind (ignored);
- X while (!feof (ignored)) { /* Check the IGNORED file first */
- X line[0] = RESET (ignored_user);
- X fgets (line, MAX_LINE - 2, ignored);
- X sscanf (line, "%s", ignored_user);
- X upcase (ignored_user);
- X if (ignored_user[0] != EOS) {
- X if (!literal_match) {
- X if (re_strcmp (ignored_user, sender, NULL) > 0) {
- X report_progress (report, tsprintf ("User %s and message ignored.\n",
- X sender), FALSE);
- X return TRUE;
- X }
- X }
- X else if (!strcmp (ignored_user, sender)) {
- X report_progress (report, tsprintf ("User %s and message ignored.\n",
- X sender), FALSE);
- X return TRUE;
- X }
- X }
- X }
- X return FALSE;
- X}
- X
- X/*
- X Check whether the list 'owner' is listed.
- X*/
- X
- XBOOLEAN owner_listed (char *owners, char *owner, char *list, FILE *report)
- X{
- X char registered_owner [MAX_LINE];
- X char assigned_list [MAX_LINE];
- X char line [MAX_LINE];
- X FILE *f;
- X
- X OPEN_FILE (f, owners, "r", "owner_listed");
- X while (!feof (f)) {
- X line[0] = assigned_list[0] = RESET (registered_owner);
- X fgets (line, MAX_LINE - 2, f);
- X sscanf (line, "%s %s", registered_owner, assigned_list);
- X upcase (registered_owner);
- X upcase (assigned_list);
- X if (registered_owner[0] != EOS)
- X if (!strcmp (registered_owner, owner) && !strcmp (assigned_list, list)) {
- X fclose (f);
- X return OWNER;
- X }
- X }
- X fclose (f);
- X return FALSE;
- X}
- X
- X/*
- X Check whether the given host appears in a hosts file.
- X*/
- X
- XBOOLEAN host_listed (char *hosts, char *host, FILE *report)
- X{
- X char _host [MAX_LINE];
- X FILE* f;
- X
- X OPEN_FILE (f, hosts, "r", "host_listed");
- X while (!feof (f)) {
- X RESET (_host);
- X fscanf (f, "%s", _host);
- X upcase (_host);
- X if (_host[0] == '#') {
- X fgets (_host, MAX_LINE - 2, f);
- X continue;
- X }
- X if (_host[0] != EOS && re_strcmp (_host, host, NULL) > 0) {
- X fclose (f);
- X return TRUE;
- X }
- X }
- X fclose (f);
- X return FALSE;
- X}
- X
- X/*
- X Look up 'sender' in the 'aliases' file. If a match is found, use
- X the alternate address.
- X*/
- X
- Xvoid check_aliases (char *aliases, char *sender)
- X{
- X char line [MAX_LINE];
- X char newalias [MAX_LINE];
- X char alias [MAX_LINE];
- X FILE *f;
- X
- X if ((f = fopen (aliases, "r")) == NULL)
- X return;
- X#ifdef GO_INTERACTIVE
- X IN_CRITICAL_SECTION ("check_aliases", SEM_LISTFILES);
- X#endif
- X upcase (sender);
- X while (!feof (f)) {
- X line[0] = alias[0] = RESET (newalias);
- X fgets (line, MAX_LINE - 2, f);
- X sscanf (line, "%s %s", alias, newalias);
- X upcase (alias);
- X if (alias[0] != EOS)
- X if (re_strcmp (alias, sender, newalias) > 0)
- X upcase (newalias),
- X strcpy (sender, newalias);
- X }
- X fclose (f);
- X#ifdef GO_INTERACTIVE
- X OUT_OF_CRITICAL_SECTION ("check_aliases", SEM_LISTFILES);
- X#endif
- X return;
- X}
- X
- X/*
- X Extract the sender's email address. To do that, skip over the leading
- X "From ". That's where the address starts. Then put an EOS character at
- X the end of this address (a blank terminates this address string).
- X Addresses that contain single quotes are treated as invalid (contrary to
- X RFC 822 specs) since they create problems with the shell.
- X*/
- X
- XBOOLEAN extract_sender (char *s)
- X{
- X int nsquote = 0, ndquote = 0, nparen = 0, nangle = 0, nsquare = 0;
- X BOOLEAN done = FALSE, invalid_char = FALSE;
- X char *r = s;
- X#ifdef DEBUG
- X char *p = s + strlen (s);
- X#endif
- X
- X if (strncmp (s, START_OF_MESSAGE, strlen (START_OF_MESSAGE))) {
- X s [strlen (START_OF_MESSAGE)] = EOS;
- X return FALSE;
- X }
- X sprintf (s, "%s", s + strlen (START_OF_MESSAGE));
- X while (*s != EOS && !done) { /* Look for end of address substring */
- X (*s == '`' || *s == '*' || *s == '?' || *s == '|' ? invalid_char = TRUE : 0);
- X/*
- X (*s == '/' && (s == r || *(s - 1) == ';') ? invalid_char = TRUE : 0);
- X*/
- X (*s == '\'' ? (nsquote = 1) : 0);
- X (*s == '\"' ? (s != r ? (*(s - 1) != '\\' ? (ndquote = !ndquote) : 0) :
- X (ndquote = !ndquote)) : 0);
- X (*s == '(' ? (!ndquote ? ++nparen : 0) : 0);
- X (*s == ')' ? (!ndquote ? --nparen : 0) : 0);
- X (*s == '<' ? (!ndquote ? ++nangle : 0) : 0);
- X (*s == '>' ? (!ndquote ? --nangle : 0) : 0);
- X (*s == '[' ? (!ndquote ? ++nsquare : 0): 0);
- X (*s == ']' ? (!ndquote ? --nsquare : 0) : 0);
- X (isspace (*s) ?
- X ((ndquote || nparen || nangle || nsquare) ? 0 : (done = TRUE)) : 0);
- X ++s;
- X#ifdef DEBUG
- X if (s > p) { /* Beyond EOS */
- X extern FILE *report;
- X report_progress (report, "extract_sender(): memory being overwritten",
- X TRUE);
- X }
- X#endif
- X }
- X *(s - 1) = EOS; /* 's' is now pointing to the sender's address */
- X if (nsquote || ndquote || nparen || nangle || nsquare || invalid_char)
- X return FALSE; /* Error in address */
- X return TRUE;
- X}
- X
- X/*
- X Extract the subscriber's address from the file. Addresses that contain
- X single quotes are treated as invalid (contrary to RFC 822 specs) since they
- X create problems with the shell.
- X*/
- X
- XBOOLEAN extract_subscriber (FILE *f, char *subscriber, BOOLEAN aliases_file)
- X{
- X int ndquote = 0, nparen = 0, nangle = 0, nsquare = 0, i = 0;
- X int nsquote = 0;
- X BOOLEAN done = FALSE, invalid_char = FALSE;
- X char c = EOS, pc;
- X
- X while (!feof (f) && !done && i < MAX_LINE) {
- X pc = c;
- X c = fgetc (f);
- X (c == '`' || c == '*' || c == '?' || c == '|' ? invalid_char = TRUE : 0);
- X/*
- X (c == '/' && (pc == EOS || pc == ';') ? invalid_char = TRUE : 0);
- X*/
- X (c == '\'' ? (nsquote = 1) : 0);
- X (c == '\"' ? (pc != '\\' ? (ndquote = !ndquote) : 0) : 0);
- X (c == '(' ? (!ndquote ? ++nparen : 0) : 0);
- X (c == ')' ? (!ndquote ? --nparen : 0) : 0);
- X (c == '<' ? (!ndquote ? ++nangle : 0) : 0);
- X (c == '>' ? (!ndquote ? --nangle : 0) : 0);
- X (c == '[' ? (!ndquote ? ++nsquare : 0): 0);
- X (c == ']' ? (!ndquote ? --nsquare : 0) : 0);
- X (isspace (c) ?
- X ((!aliases_file && (ndquote || nparen || nangle || nsquare)) ? 0
- X : (done = TRUE)) : 0);
- X subscriber [i++] = c;
- X }
- X if (i > 0)
- X subscriber [i - 1] = EOS;
- X if (!aliases_file &&
- X (nsquote || ndquote || nparen || nangle || nsquare || invalid_char))
- X return FALSE; /* Error in address */
- X return TRUE;
- X}
- X
- X/*
- X Extract the originator of the message, i.e. the list that the original
- X message first originated from.
- X*/
- X
- Xvoid extract_origin (char *s)
- X{
- X char *p;
- X
- X if (p = strchr (s, '<'))
- X sprintf (s, "%s", p + 1); /* Remove '<' */
- X if (p = strchr (s, '>'))
- X *p = EOS; /* Remove '>' */
- X else { /* Get to the end of the address */
- X while (*s != EOS && !isspace (*s))
- X ++s;
- X *s = EOS;
- X }
- X}
- X
- X/*
- X Given an RFC 822 From: line address, strip comments etc. and extract
- X the actual address.
- X*/
- X
- Xvoid extract_address (char *s)
- X{
- X char *p;
- X
- X if (p = strchr (s, '<'))
- X sprintf (s, "%s", p + 1); /* Remove '<' */
- X if (*s == '|' || *s == ':')
- X *s = EOS; /* Protect against trojans */
- X if (p = strchr (s, '>'))
- X *p = EOS; /* Remove '>' */
- X if (p = strchr (s, '('))
- X *p = EOS; /* Remove comments */
- X while (*s != EOS && !isspace (*s)) /* Get to the end of the address */
- X ++s;
- X *s = EOS;
- X}
- X
- X/*
- X Scan 's' and escape the following characters:
- X ( ) [ ] < > { } \ : ; ' ` . ^ $ *
- X*/
- X
- Xvoid escape_address (char *s)
- X{
- X char *r;
- X
- X while (*s != EOS) {
- X switch (*s) {
- X case '(': case ')': case '[': case ']': case '<': case '>': case '\\':
- X case ':': case ';': case '\'': case '`': case '.': case '^':
- X case '$': case '*': case '{': case '}':
- X r = s + strlen (s); /* Start from the end */
- X while (r != s)
- X *(r + 1) = *r,
- X --r;
- X *(r + 1) = *r;
- X *r = '\\';
- X ++s;
- X break;
- X }
- X ++s;
- X }
- X}
- *-*-END-of-src/sender.c-*-*
- echo x - src/serverd.c
- sed 's/^X//' >src/serverd.c <<'*-*-END-of-src/serverd.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | LISTPROCESSOR SYSTEM DAEMON |
- X | |
- X | Version 5.1 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X | |
- X | Enhanced by: Warren Burstein. |
- X ----------------------------------------------------------------------------
- X
- X Spawn list or listproc upon arrival of new messages. Send mail to
- X MANAGER if something went wrong (only if using UCB mail).
- X serverd will not spawn if the current load average is above max_load
- X and the -l flag is on, until it has delayed MAX_TRIES * 30 seconds.
- X serverd communicates with listerv via exit statuses 6 and 7; these are
- X the requests to shutdown/restart the system; on status 7, serverd spawns
- X start and dies; if it cannot restart, it sends mail and commits suicide.
- X serverd reports to REPORT_SERVERD.
- X
- X The server may also run in interactive mode and listen for TCP connections
- X at a specified port. Users are able of entering requests and getting replies
- X live. For this, a separate listener process is spawned which accepts or
- X rejects the connections, then it in turn forks off children to handle
- X accepted connections.
- X
- X Master process (looks for email requests/messages)
- X |
- X Listener (accepts or rejects connection requests)
- X |
- X /|\
- X children (process live requests)
- X
- X If the Master process dies in any way but a SIGKILL signal, then all
- X processes abort. If the Listener process dies (including a SIGKILL signal),
- X all processes abort as well. If the Master is killed with SIGKILL, behavior
- X will be undefined and a semaphore will be left unused in the system (use
- X ipcrm to remove it). If any of the children die abnormally (including a
- X SIGKILL signal) the Listener process will report to that effect; however,
- X the connection will remain "open" on the other end until it times out
- X locally.
- X
- X A "restart" or "shutdown" request (live or not) will kill all processes and
- X in the case of "restart", a new Master and Listener will be created.
- X
- X Synchronization between all processes is done via a semaphore. Removing or
- X altering the semaphore while the system is running will bring the system
- X down.
- X
- X COMMAND LINE OPTIONS:
- X -1: Execute only once -- to be used with cron.
- X -l: Enforce restrictions based on the current load average.
- X -e: Echo reports to the screen.
- X -i: Interactive server; it listens for tcp connections. The argument
- X that follows is the maximum duration (in seconds) of each connection.
- X
- X EXIT CODES:
- X 0: OK
- X 1: Could not open or lock file
- X 2: SIGINT signal
- X 3: Command line option error
- X 4: Syntax error in file
- X 5: Could not spawn
- X 6: Shutdown request
- X 7: Restart request
- X 8: Received system signal
- X 9: Too many multiple recipients
- X 10: Could not deliver mail
- X 11: Malloc failed
- X 12: Cannot fork
- X 13: Socket connection problem
- X 14: Semaphore error
- X 15: Cannot setuid, setgid
- X 16: Internal error
- X
- X*/
- X
- X#include <stdio.h>
- X#ifdef SYSLOG
- X# ifdef ultrix
- X# include <sys/syslog.h>
- X# else
- X# include <syslog.h>
- X# endif
- X#endif
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <sys/types.h>
- X#if defined (stardent) || defined (stellar) || defined (titan)
- X# include <rpc/types.h>
- X#endif
- X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
- X && !defined (sequent) && !defined (unknown_port)
- X# include <malloc.h>
- X#endif
- X#include <sys/stat.h>
- X#include <signal.h>
- X#include <fcntl.h>
- X#include <time.h>
- X#include <ctype.h>
- X#include <string.h>
- X#include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X#include <math.h>
- X#include <sys/wait.h>
- X#if !defined (sequent) && !defined (__NeXT__) && !defined (__convex__) && \
- X !defined (apollo) && !defined (i386) && !defined (unknown_port)
- X# include <sys/termio.h>
- X#endif
- X#ifndef sun
- X# include <sys/ioctl.h>
- X#endif
- X#include "defs.h"
- X#include "serverd.h"
- X#include "struct.h"
- X#include "global.h"
- X#if defined (__NeXT__) || defined (unknown_port)
- X# include "next.h"
- X#endif
- X
- X#ifdef GO_INTERACTIVE
- X# include <sys/socket.h>
- X# ifndef stellar
- X# include <sys/time.h>
- X# endif
- X# include <netinet/in.h>
- X# include <netdb.h>
- X# include <sys/ipc.h>
- X# include <sys/sem.h>
- X# include <pwd.h>
- X#endif
- X
- X#ifdef __STDC__
- X# include <stdarg.h>
- Xextern int syscom (char *, ...);
- Xextern char *tsprintf (char *, ...);
- X#else
- X# include <varargs.h>
- Xextern int syscom ();
- Xextern char *tsprintf ();
- X#endif
- X
- X#if !defined (__NeXT__) && !defined (__osf__) && !defined (_AIX)
- Xextern double atof ();
- Xextern long int atoi (char *);
- X#else
- Xextern int atoi (const char *);
- X#endif
- Xextern int sys_config (FILE *, SYS *);
- Xextern int _getopt (int, char **, char *);
- Xextern void setup_string (char *, char *, char *);
- Xextern void init_signals (void);
- Xextern void catch_signals (void);
- Xextern void report_progress (FILE *, char *, int);
- Xextern int lock_file (char *, int, int, BOOLEAN);
- Xextern void unlock_file (int);
- Xextern void clean_request (char *);
- Xextern char *upcase (char *);
- Xextern BOOLEAN owner_listed (char *, char *, char *, FILE *);
- Xextern BOOLEAN host_listed (char *, char *, FILE *);
- Xextern BOOLEAN subscribed (FILE *, char *, char *, char *, char *, char *,
- X BOOLEAN);
- Xextern int long write_to_fd (int, char *, long int);
- Xextern int otoi (char *);
- Xextern char *_strstr (char *, char *);
- Xextern void my_abort (int);
- Xextern int echo (char *, char *);
- Xextern int cat_append (char *, char *);
- Xextern int re_strcmp (char *, char *, char *);
- Xextern int insert_word (char *, char **, int, int, int);
- Xextern char *mystrdup (char *);
- Xextern int semtran (int);
- Xextern void semremove (int);
- Xextern int prevch (char *, char *);
- Xextern int nextch (char *);
- X
- X
- Xvoid main (int, char **, char **);
- Xvoid serverd_config (void);
- Xvoid usage (void);
- Xint gexit (int);
- Xvoid load_wait (float);
- Xvoid run_program (char *, BOOLEAN, int);
- X#ifdef GO_INTERACTIVE
- Xvoid sighandle (int);
- Xvoid listener_exited (void);
- Xvoid close_connection (int);
- Xint check_timeout (CLIENT []);
- Xint create_connection (void);
- Xvoid process_live_request (int, struct sockaddr_in);
- XBOOLEAN check_for_redirection (char *, char *, int *, int, BOOLEAN);
- XBOOLEAN writeable_file (char *, int);
- XBOOLEAN child_alive (int, CLIENT []);
- XBOOLEAN still_delivering_mail (int);
- X#endif
- X
- X
- Xvoid main (int argc, char **argv, char **envp)
- X{
- X struct stat stat_buf;
- X int rlfd = 2;
- X FILE *f, *fp;
- X float max_load;
- X BOOLEAN loadr = FALSE, execute_once = FALSE, already_aborted;
- X char list [MAX_LINE];
- X char server [MAX_LINE], fulldate [MAX_LINE];
- X char msg [4096];
- X char *mask, *ch;
- X int c;
- X#ifdef GO_INTERACTIVE
- X char *options = "1l:i:e", *s, reply [MAX_LINE], version [MAX_LINE];
- X char welcome [65536];
- X int connid = 0, port, l, pid, _nforks;
- X struct sockaddr_in client;
- X struct hostent *hp;
- X union semun {
- X int val;
- X struct semid_ds *buf;
- X ushort *array;
- X } sembuf;
- X int smask;
- X#else
- X char *options = "1l:e";
- X#endif
- X#ifdef ultrix
- X time_t time_is = 0;
- X#else
- X long int time_is = 0;
- X#endif
- X long int current_date = -1, new_date, time_then = 0;
- X struct tm *t;
- X extern char *optarg, *getenv();
- X extern int optopt;
- X int i, j, current_list;
- X
- X prog = argv[0];
- X while ((c = _getopt (argc, argv, options)) != EOF)
- X switch ((char) c) {
- X case '1': execute_once = TRUE; break;
- X case 'e': tty_echo = TRUE; break;
- X case 'l': loadr = TRUE;
- X max_load = (float) atof (optarg);
- X break;
- X#ifdef GO_INTERACTIVE
- X case 'i':
- X interactive = TRUE;
- X if ((conn_duration = atoi (optarg)) <= 0)
- X fprintf (stderr, "-i %d ???\n", conn_duration),
- X exit (3);
- X break;
- X#endif
- X case ':':
- X fprintf (stderr, "serverd: Option '%c' requires an argument.\n",
- X optopt);
- X exit (3);
- X case '?':
- X default:
- X usage ();
- X }
- X if ((mask = getenv ("ULISTPROC_UMASK")))
- X umask (otoi (mask));
- X else
- X mask = "066",
- X umask (S_IRWXG|S_IRWXO); /* 600 */
- X#ifndef NO_LOCKS
- X if ((lfd = lock_file (SERVERD_LOCK_FILE, O_RDWR, 0, FALSE)) < 0)
- X fprintf (stderr, "serverd: Unable to lock %s. Aborting.\n",
- X SERVERD_LOCK_FILE),
- X exit (2);
- X#endif
- X#ifdef SYSLOG
- X openlog ("ListProcessor: serverd", LOG_NDELAY
- X# ifndef i386
- X |LOG_NOWAIT
- X# endif
- X , SYSLOG);
- X# ifndef ultrix
- X setlogmask (LOG_UPTO (LOG_INFO));
- X# endif
- X#else
- X if ((report = fopen (REPORT_SERVERD, "a")) == NULL)
- X fprintf (stderr, "serverd: Could not open %s\n", REPORT_SERVERD),
- X exit (1);
- X chmod (REPORT_SERVERD, 384);
- X fprintf (report, "%s", COPYRIGHT);
- X fflush (report);
- X#endif
- X
- X#ifdef GO_INTERACTIVE
- X if ((pwentry = getpwuid (getuid ())) == NULL)
- X report_progress (report, "main(): Invalid user account", TRUE),
- X exit (3);
- X# ifndef SYSLOG
- X if (chown (REPORT_SERVERD, pwentry->pw_uid, pwentry->pw_gid))
- X report_progress (report, "\nmain(): Cannot chown()", TRUE),
- X exit (15);
- X# endif
- X#endif
- X if ((f = fopen (PID_SERVERD, "w")) != NULL)
- X fprintf (f, "%d", getpid()),
- X fclose (f)
- X#ifdef GO_INTERACTIVE
- X ,chown (PID_SERVERD, pwentry->pw_uid, pwentry->pw_gid);
- X#else
- X ;
- X#endif
- X
- X signal (SIGINT, (void (*)()) gexit);
- X#ifdef GO_INTERACTIVE
- X# if defined (bsd)
- X sigsetmask (0);
- X# elif defined (svr3) || defined (svr4)
- X# ifdef SIGCLD
- X sigrelse (SIGCLD);
- X# else
- X sigrelse (SIGCHLD);
- X# endif
- X# endif
- X# ifdef SIGCLD
- X signal (SIGCLD, (void (*)()) sighandle);
- X# else
- X signal (SIGCHLD, (void (*)()) sighandle);
- X# endif
- X signal (ABORT_SIG, (void (*)()) listener_exited);
- X#endif
- X init_signals();
- X catch_signals ();
- X
- X time (&time_is);
- X
- X nlists = sys_config (report, &sys);
- X if (sys.fax.prog[0] == EOS)
- X strcat (sys.server.cmdoptions, " -d fax");
- X
- X if (!tty_echo) {
- X j = -1;
- X#if defined (TIOCNOTTY) && defined (SIGTTOU) && defined (SIGTTIN)
- X if ((i = open ("/dev/tty", 2)) >= 0)
- X j = ioctl (i, TIOCNOTTY, 0),
- X close (i);
- X#endif
- X if (j < 0 &&
- X#ifdef svr4
- X setsid ()
- X#else
- X# ifdef SETPGRP_NEEDS_ARGS
- X setpgrp (0, 0)
- X# else
- X setpgrp ()
- X# endif
- X#endif
- X < 0)
- X report_progress (report, "WARNING: could not detach from tty", TRUE);
- X }
- X
- X ppid = getpid ();
- X#ifdef GO_INTERACTIVE
- X if (interactive) { /* Spawn Listener process */
- X if ((sid = semtran (0)) < 0) /* Get semaphore id */
- X report_progress (report, tsprintf ("\nmain(): semget() failed; errno %d",
- X errno), TRUE),
- X exit (14);
- X if ((sembuf.buf = (struct semid_ds *) malloc (sizeof (struct semid_ds))) ==
- X NULL)
- X report_progress (report, "\nmain(): malloc() failed", TRUE),
- X exit (11);
- X sembuf.buf->sem_perm.uid = pwentry->pw_uid;
- X sembuf.buf->sem_perm.gid = pwentry->pw_gid;
- X sembuf.buf->sem_perm.mode = 0600;
- X if (semctl (sid, 1, IPC_SET, sembuf)) /* Change owner to server */
- X report_progress (report, tsprintf ("\nmain(): semctl() failed; errno %d",
- X errno), TRUE),
- X exit (14);
- X free ((struct semid_ds *) sembuf.buf);
- X
- X if (getuid () & geteuid ())
- X report_progress (report, "WARNING: serverd not started with root \
- Xprivileges", TRUE);
- X if ((chpid = fork()) < 0)
- X report_progress (report, "\nmain(): Master process cannot fork Listener \
- Xprocess", TRUE),
- X exit (12);
- X else if (chpid == 0) { /* Child process */
- X chpid = getpid (); /* Set for signal handling purposes */
- X signal (SIGINT, (void (*)()) sighandle);
- X# ifdef SIGCLD
- X signal (SIGCLD, (void (*)()) sighandle);
- X# else
- X signal (SIGCHLD, (void (*)()) sighandle);
- X# endif
- X signal (SIGTERM, (void (*)()) sighandle);
- X signal (SIGSEGV, (void (*)()) sighandle);
- X signal (SIGILL, (void (*)()) sighandle);
- X signal (SIGQUIT, (void (*)()) sighandle);
- X signal (SIGBUS, (void (*)()) sighandle);
- X strcpy (version, VERSION);
- X ch = strchr (version, ' ');
- X *ch = EOS;
- X
- X if ((sock_fd = create_connection ()) < 0)
- X report_progress (report, "\nmain(): Listener process cannot create \
- Xconnection", TRUE),
- X kill (ppid, ABORT_SIG),
- X exit (13);
- X if (setuid (pwentry->pw_uid) || setgid (pwentry->pw_gid))
- X report_progress (report, "\nmain(): Listener process cannot \
- Xsetuid()/setgid()", TRUE),
- X kill (ppid, ABORT_SIG),
- X exit (15);
- X while (007) { /* Listen for ever */
- X
- X l = sizeof (client);
- X if ((msg_sock = accept (sock_fd, (struct sockaddr *) &client,
- X (int *) &l)) < 0) {
- X if (errno != EINTR
- X#ifdef ERESTART
- X && errno != ERESTART
- X#endif
- X )
- X report_progress (report, "\nmain(): Listener process cannot accept()",
- X TRUE),
- X kill (ppid, ABORT_SIG),
- X exit (13);
- X continue;
- X }
- X else { /* New client; see if we can handle it */
- X hp = gethostbyaddr ((char *) &client.sin_addr,
- X sizeof (struct in_addr), client.sin_family);
- X report_progress (report,
- X tsprintf ("Connection request from %s: ",
- X upcase ((s = (hp ? hp->h_name :
- X (char *) inet_ntoa (client.sin_addr))))),
- X FALSE);
- X if (!stat (PRIVILEGED_HOSTSF, &stat_buf))
- X if (!host_listed (PRIVILEGED_HOSTSF, s, report)) {
- X CANNOT_CONNECT ("not a privileged host", CONN_ABORTED,
- X "Not a privileged host.\n");
- X continue;
- X }
- X if (host_listed (UNWANTED_HOSTSF, s, report)) {
- X CANNOT_CONNECT ("unwanted host", CONN_ABORTED,
- X "Not a privileged host.\n");
- X continue;
- X }
- X
- X if (nforks < 0 || nforks > MAX_CONNECTIONS)
- X report_progress (report, tsprintf ("\nmain(): Listener process: \
- Xinternal error: nforks=%d", nforks), TRUE),
- X kill (ppid, ABORT_SIG),
- X exit (16);
- X if (nforks + 1 > MAX_CONNECTIONS) { /* Too many connections */
- X if ((pid = check_timeout (clients)) > 0) {
- X kill (pid, TIMEOUT_SIG); /* Tell it to commit suicide */
- X while (child_alive (pid, clients)); /* Wait */
- X }
- X else { /* No children have timed out, so tough */
- X CANNOT_CONNECT ("refused", SERVER_BUSY, SERVER_BUSY_);
- X continue;
- X }
- X }
- X report_progress (report, tsprintf ("connected (client #%d)", connid),
- X TRUE);
- X /* Parent increments the number of times it has forked */
- X _nforks = nforks;
- X clients [nforks].time = time (0); /* Save time child spawned */
- X clients [nforks].connid = connid++;
- X strcpy (clients [nforks++].name,
- X (hp ? hp->h_name : (char *) inet_ntoa (client.sin_addr)));
- X# if defined (bsd)
- X# ifdef SIGCLD
- X smask = sigblock (sigmask (SIGCLD));
- X# else
- X smask = sigblock (sigmask (SIGCHLD));
- X# endif
- X# elif defined (svr4) || defined (svr3)
- X# ifdef SIGCLD
- X sighold (SIGCLD);
- X# else
- X sighold (SIGCHLD);
- X# endif
- X# endif
- X if ((pid = fork ()) < 0) { /* fork */
- X CANNOT_CONNECT ("cannot fork", SYS_ERROR, "Remote system error.\n");
- X# if defined (bsd)
- X sigsetmask (smask);
- X# elif defined (svr3) || defined (svr4)
- X# ifdef SIGCLD
- X sigrelse (SIGCLD);
- X# else
- X sigrelse (SIGCHLD);
- X# endif
- X# endif
- X continue;
- X }
- X else if (pid == 0) { /* Child process */
- X close (sock_fd); /* Close unused parent socket */
- X# ifdef SIGCLD
- X signal (SIGCLD, SIG_DFL);
- X# else
- X signal (SIGCHLD, SIG_DFL);
- X# endif
- X signal (TIMEOUT_SIG, (void (*)()) close_connection);
- X signal (ABORT_SIG, (void (*)()) close_connection);
- X signal (SIGALRM, (void (*)()) close_connection);
- X signal (SIGPIPE, (void (*)()) close_connection);
- X signal (SIGINT, (void (*)()) SIG_IGN);
- X signal (SIGTERM, (void (*)()) close_connection);
- X signal (SIGSEGV, (void (*)()) close_connection);
- X signal (SIGILL, (void (*)()) close_connection);
- X signal (SIGQUIT, (void (*)()) close_connection);
- X signal (SIGBUS, (void (*)()) close_connection);
- X alarm (conn_duration);
- X time_is = time (0);
- X sprintf (welcome, "%s interactive ListProcessor.\nVersion %s %s\
- XMaximum connection duration is %d seconds.\n",
- X sys.organization, version, ctime (&time_is),
- X conn_duration);
- X if ((f = fopen (WELCOMEF, "r"))) {
- X while (!feof (f))
- X fgets (welcome + strlen (welcome), MAX_LINE, f);
- X fclose (f);
- X }
- X sprintf (msg, "%d %d %s %d %d\n%d %d \n\n%s", CONNECT,
- X conn_duration, version, strlen (PROMPT),
- X strlen (CONT_PROMPT), OK,
- X strlen (welcome) +
- X strlen (LOGIN) + 1, welcome);
- X if (write_to_fd (msg_sock, msg, strlen (msg)) < 0)
- X CLIENT_LOST (13);
- X process_live_request (msg_sock, client);
- X }
- X else
- X clients [_nforks].pid = pid,
- X# if defined (bsd)
- X sigsetmask (smask),
- X# elif defined (svr3) || defined (svr4)
- X# ifdef SIGCLD
- X sigrelse (SIGCLD),
- X# else
- X sigrelse (SIGCHLD),
- X# endif
- X# endif
- X close (msg_sock);
- X }
- X }
- X }
- X }
- X#endif
- X
- X#ifdef GO_INTERACTIVE
- X if (setuid (pwentry->pw_uid) || setgid (pwentry->pw_gid))
- X report_progress (report, "\nmain(): Master process cannot \
- Xsetuid()/setgid()", TRUE),
- X gexit (15);
- X#endif
- X
- X serverd_config ();
- X current_list = -1;
- X while (007) {
- X
- X if ((++current_list) == nlists)
- X current_list = 0;
- X
- X if (!stat (lists[current_list].list_mail_f, &stat_buf) &&
- X stat_buf.st_size > 0 &&
- X (rlfd = lock_file (lists[current_list].list_mail_f, O_RDWR, 0, FALSE)) >= 0) {
- X unlock_file (rlfd);
- X
- X if (sys.lists[current_list].max_messages) {
- X time (&time_is);
- X t = localtime (&time_is);
- X new_date = t->tm_mon + 1 + t->tm_mday + t->tm_year;
- X if (new_date != lists[current_list].current_date)
- X lists[current_list].nmessages = 0,
- X lists[current_list].done_for_the_day = FALSE,
- X lists[current_list].current_date = new_date,
- X echo (tsprintf ("0 %d %d %d", t->tm_mon + 1, t->tm_mday,
- X t->tm_year),
- X lists[current_list].list_limitsf);
- X if (!lists[current_list].done_for_the_day) {
- X if ((f = fopen (lists[current_list].list_limitsf, "r"))) {
- X fscanf (f, "%d", &lists[current_list].nmessages);
- X fclose (f);
- X }
- X if (lists[current_list].nmessages >= sys.lists[current_list].max_messages) {
- X lists[current_list].done_for_the_day = TRUE;
- X lists[current_list].nmessages = 0;
- X goto xxx;
- X }
- X }
- X else
- X goto xxx;
- X }
- X
- X time_is = time (0);
- X sprintf (fulldate, "%s", ctime (&time_is));
- X if ((ch = strchr (fulldate, '\n')))
- X *ch = EOS;
- X report_progress (report, tsprintf ("\n--- NEW MAIL FOR %s on %s ---\n",
- X sys.lists[current_list].alias,
- X fulldate), FALSE);
- X
- X if (loadr) /* enforce restrictions */
- X load_wait (max_load);
- X
- X RESET (list);
- X sprintf (list, "%s %s %s", LIST, sys.lists[current_list].alias,
- X sys.lists[current_list].cmdoptions);
- X#ifdef GO_INTERACTIVE
- X if (interactive)
- X sprintf (list + strlen (list), " -S %d", sid);
- X#endif
- X run_program (list, FALSE, -1);
- X xxx: ;
- X }
- X/*
- X if (sys.frequency > 0)
- X sleep (sys.frequency); do a quickie to The Spy Who Loved Him
- X*/
- X if (!stat (lists[current_list].digest_msgf, &stat_buf) && stat_buf.st_size > 0) {
- X /*
- X Something in the digest message file, see how long it's been
- X since last message was sent by reading digest_timef.
- X */
- X if (fp = fopen (lists[current_list].digest_timef, "r"))
- X fscanf (fp, "%ld\n", &time_then),
- X fclose (fp);
- X if ((time(0) - time_then) / 3600 >= sys.lists[current_list].digest_hours) {
- X report_progress (report,
- X tsprintf ("\n--- DIGEST TIME REACHED FOR %s ---\n",
- X sys.lists[current_list].alias), FALSE);
- X
- X if (loadr)
- X load_wait (max_load);
- X
- X RESET (list);
- X sprintf (list, "%s %s %s -d", LIST, sys.lists[current_list].alias,
- X sys.lists[current_list].cmdoptions);
- X#ifdef GO_INTERACTIVE
- X if (interactive)
- X sprintf (list + strlen (list), " -S %d", sid);
- X#endif
- X run_program (list, FALSE, -1);
- X }
- X }
- X
- X if (!stat (BATCH_FILE, &stat_buf) && stat_buf.st_size > 0) {
- X time (&time_is);
- X t = localtime (&time_is);
- X new_date = t->tm_mon + 1 + t->tm_mday + t->tm_year;
- X if (new_date != current_date) { /* Process batch on new day only */
- X current_date = new_date; /* New day or first time through loop */
- X report_progress (report, "\n--- PROCESSING THE BATCH QUEUE ---\n",
- X FALSE);
- X RESET (server);
- X sprintf (server, "%s %s -B", SERVER, sys.server.cmdoptions);
- X#ifdef GO_INTERACTIVE
- X if (interactive)
- X sprintf (server + strlen (server), " -S %d", sid);
- X#endif
- X run_program (server, TRUE, -1);
- X }
- X }
- X
- X if (!stat (SERVER_MAIL_FILE, &stat_buf) && stat_buf.st_size > 0 &&
- X (rlfd = lock_file (SERVER_MAIL_FILE, O_RDWR, 0, FALSE)) >= 0) {
- X unlock_file (rlfd);
- X
- X time (&time_is);
- X t = localtime (&time_is);
- X new_date = t->tm_mon + 1 + t->tm_mday + t->tm_year;
- X current_date = new_date; /* New day or first time through loop */
- X time_is = time (0);
- X sprintf (fulldate, "%s", ctime (&time_is));
- X if ((ch = strchr (fulldate, '\n')))
- X *ch = EOS;
- X report_progress (report,
- X tsprintf ("\n--- NEW MAIL FOR SERVER on %s ---\n", fulldate), FALSE);
- X
- X if (loadr) /* Enforce restrictions */
- X load_wait (max_load);
- X
- X RESET (server);
- X sprintf (server, "%s %s", SERVER, sys.server.cmdoptions);
- X#ifdef GO_INTERACTIVE
- X if (interactive)
- X sprintf (server + strlen (server), " -S %d", sid);
- X#endif
- X run_program (server, TRUE, -1);
- X }
- X
- X if (execute_once && current_list == 0)
- X gexit (0);
- X if (sys.frequency > 0)
- X sleep (sys.frequency); /* do a quickie to Money Penny */
- X }
- X}
- X
- Xvoid serverd_config ()
- X{
- X int i, mon, day, year;
- X FILE *f;
- X
- X for (i = 0; i < nlists; ++i) {
- X setup_string (lists[i].list_mail_f, sys.lists[i].alias, LIST_MAIL_FILE);
- X setup_string (lists[i].digest_msgf, sys.lists[i].alias, DIGEST_MSG);
- X setup_string (lists[i].digest_timef, sys.lists[i].alias, DIGEST_TIME);
- X setup_string (lists[i].list_limitsf, sys.lists[i].alias, LIST_LIMITS);
- X lists[i].nmessages = mon = day = year = 0;
- X lists[i].done_for_the_day = FALSE;
- X if ((f = fopen (lists[i].list_limitsf, "r")))
- X fscanf (f, "%d %d %d %d", &lists[i].nmessages, &mon, &day, &year),
- X fclose (f);
- X lists[i].current_date = mon + day + year;
- X }
- X}
- X
- Xvoid usage ()
- X{
- X#ifdef GO_INTERACTIVE
- X fprintf (stderr, "Usage: serverd [-1] [-e] [-l load] [-i duration]\n\
- X-1: Execute only once.\n\
- X-e: Echo reports to the screen.\n\
- X-l: Enforce load restrictions.\n\
- X-i: Go into interactive mode also; listen for TCP connections;\n\
- X each connection is limited to 'duration' seconds.\n");
- X#else
- Xfprintf (stderr, "Usage: serverd [-1] [-e] [-l load]\n\
- X-1: Execute only once.\n\
- X-e: Echo reports to the screen.\n\
- X-l: Enforce load restrictions.\n");
- X#endif
- X exit (3);
- X}
- X
- X/*
- X Graceful exit. Remove pid file.
- X*/
- X
- Xint gexit (int exitcode)
- X{
- X unlink (PID_SERVERD);
- X#ifndef NO_LOCKS
- X unlock_file (lfd);
- X#endif
- X#ifdef GO_INTERACTIVE
- X if (interactive) {
- X kill (chpid, SIGINT);
- X while (!chdied);
- X semremove (sid);
- X }
- X#endif
- X exit (exitcode);
- X}
- X
- X/*
- X Wait MAX_TRIES * 30 seconds for load to drop to max_load.
- X*/
- X
- Xvoid load_wait (float max_load)
- X{
- X int try;
- X float load = 0.0;
- X FILE *loadf;
- X
- X for (try = 0 ;; try++) {
- X syscom ("%s | %s \
- X'{ \
- X for (i = 1; i < 20; ++i) \
- X if ($i == \"load\") \
- X if ($(i+1) == \"average:\") print $(i+2);\
- X else print $(i+1); \
- X}' > %s",
- X UPTIME, AWK, LOAD_FILE);
- X OPEN_FILE (loadf, LOAD_FILE, "r", "load_wait");
- X fscanf (loadf, "%f", &load);
- X fclose (loadf);
- X unlink (LOAD_FILE);
- X
- X if (load <= max_load)
- X break;
- X
- X sleep (30);
- X }
- X}
- X
- X/*
- X Execute 'command' using the system call.
- X
- X USER CONTRIBUTED MODIFIED CODE (for version 5.5): Warren Burstein.
- X*/
- X
- X#define MYWEXITSTATUS(stat) ((int)(((stat)>>8)&0377))
- X
- Xvoid run_program (char *command, BOOLEAN is_listproc, int msg_sock)
- X{
- X int status, mask;
- X char msg [MAX_LINE];
- X char reply [MAX_LINE];
- X
- X report_progress (report, command, TRUE);
- X
- X#ifdef GO_INTERACTIVE
- X if (ppid == getpid())
- X# if defined (bsd)
- X# ifdef SIGCLD
- X mask = sigblock (sigmask (SIGCLD)),
- X# else
- X mask = sigblock (sigmask (SIGCHLD)),
- X# endif
- X status = system (command),
- X sigsetmask (mask);
- X# elif (defined (svr4) || defined (svr3)) && !defined (stellar)
- X# ifdef SIGCLD
- X sighold (SIGCLD),
- X# else
- X sighold (SIGCHLD),
- X# endif
- X status = system (command),
- X# ifdef SIGCLD
- X sigrelse (SIGCLD);
- X# else
- X sigrelse (SIGCHLD);
- X# endif
- X# else
- X# ifdef SIGCLD
- X signal (SIGCLD, SIG_DFL),
- X# else
- X signal (SIGCHLD, SIG_DFL),
- X# endif
- X status = system (command),
- X# ifdef SIGCLD
- X signal (SIGCLD, (void (*)()) sighandle);
- X# else
- X signal (SIGCHLD, (void (*)()) sighandle);
- X# endif
- X# endif
- X else
- X#endif
- X status = system (command);
- X if (status > 127) {
- X sprintf (msg, "%s %s: %s: %s",
- X (ppid == getpid() ? "serverd" : "ILP client"),
- X (MYWEXITSTATUS (status) == 7) ? "restarts" : "died",
- X is_listproc ? "LISTPROC" : "LIST",
- X (MYWEXITSTATUS (status) >= 0 && MYWEXITSTATUS (status) <= 16 ?
- X exit_string[MYWEXITSTATUS (status)] : exit_string[17]));
- X report_progress (report, msg, TRUE);
- X if (sys.options & BSD_MAIL)
- X syscom ("echo '' | %s -s '%s' %s", UCB_MAIL, msg, sys.manager);
- X
- X if (is_listproc) {
- X if (MYWEXITSTATUS (status) == 6) { /* Shutdown request */
- X#ifdef SYSLOG
- X closelog ();
- X#else
- X fclose (report);
- X#endif
- X#ifdef GO_INTERACTIVE
- X if (interactive) {
- X CLOSE_CLIENT (msg_sock);
- X if (ppid == getpid()) /* Master process notifies */
- X gexit (6); /* It will kill chpid */
- X exit (6);
- X }
- X#endif
- X gexit (6);
- X }
- X
- X if (MYWEXITSTATUS (status) == 7) { /* Restart request */
- X unlink (PID_SERVERD);
- X#ifndef NO_LOCKS
- X unlock_file (lfd);
- X#endif
- X#ifdef GO_INTERACTIVE
- X if (interactive) {
- X CLOSE_CLIENT (msg_sock);
- X if (ppid == getpid()) { /* Master process notifies and continues */
- X# ifdef SIGCLD
- X signal (SIGCLD, SIG_DFL);
- X# else
- X signal (SIGCHLD, SIG_DFL);
- X# endif
- X kill (chpid, SIGINT);
- X while (!chdied);
- X semremove (sid);
- X }
- X else
- X exit (7);
- X }
- X#endif
- X signal (SIGALRM, SIG_IGN); /* Just in case */
- X execl (START, START, START_OPTIONS, NULL);
- X sprintf (msg, "serverd commits suicide: Could not restart \
- Xsystem");
- X report_progress (report, msg, TRUE);
- X#ifdef SYSLOG
- X closelog ();
- X#else
- X fclose (report);
- X#endif
- X if (sys.options & BSD_MAIL)
- X syscom ("echo '' | %s -s '%s' %s", UCB_MAIL, msg, sys.manager);
- X#ifdef GO_INTERACTIVE
- X if (interactive)
- X exit (5);
- X#endif
- X gexit (5);
- X }
- X }
- X#ifdef SYSLOG
- X closelog ();
- X#else
- X fclose (report);
- X#endif
- X#ifdef GO_INTERACTIVE
- X if (interactive) {
- X CLOSE_CLIENT (msg_sock);
- X if (ppid == getpid()) /* Master process notifies */
- X gexit (MYWEXITSTATUS (status)); /* Will kill chpid */
- X exit (MYWEXITSTATUS (status));
- X }
- X#endif
- X gexit (MYWEXITSTATUS (status));
- X }
- X
- X if (status == 127) {
- X sprintf (msg, "serverd died: could not execute shell for %s",
- X is_listproc ? "listproc" : "list");
- X if (sys.options & BSD_MAIL)
- X syscom ("echo '' | %s -s '%s' %s", UCB_MAIL, msg, sys.manager);
- X report_progress (report, msg, TRUE);
- X#ifdef SYSLOG
- X closelog ();
- X#else
- X fclose (report);
- X#endif
- X#ifdef GO_INTERACTIVE
- X if (interactive)
- X exit (5);
- X#endif
- X gexit (5);
- X }
- X else if (status > 0 && status < 127) {
- X sprintf (msg, "serverd commits suicide: status %d while trying to \
- Xspawn %s: no tty; see the documentation", status, command);
- X report_progress (report, msg, TRUE);
- X#ifdef SYSLOG
- X closelog ();
- X#else
- X fclose (report);
- X#endif
- X#ifdef GO_INTERACTIVE
- X if (interactive)
- X exit (5);
- X#endif
- X gexit (5);
- X }
- X else if (status < 0)
- X report_progress (report, "Cannot get child exit status", TRUE);
- X}
- X
- X#ifdef GO_INTERACTIVE
- X/*
- X Handle signals, especially SIGCLD.
- X*/
- X
- Xvoid sighandle (int sig)
- X{
- X#ifdef WAIT3_NEEDS_UNION
- X union wait status;
- X#else
- X int status = 1;
- X#endif
- X int pid, i, j, _nforks, mask, pids[MAX_CONNECTIONS], exstatus;
- X char reply [MAX_LINE];
- X BOOLEAN restart = FALSE;
- X
- X# ifdef SIGCLD
- X if (sig != SIGCLD)
- X signal (sig, SIG_IGN);
- X if (sig == SIGCLD) {
- X# else
- X if (sig != SIGCHLD)
- X signal (sig, SIG_IGN);
- X if (sig == SIGCHLD) {
- X# endif
- X# if defined (bsd)
- X# ifdef SIGCLD
- X mask = sigblock (sigmask (SIGCLD));
- X# else
- X mask = sigblock (sigmask (SIGCHLD));
- X# endif
- X# elif defined (svr4) || defined (svr3)
- X# ifdef SIGCLD
- X sighold (SIGCLD);
- X# else
- X sighold (SIGCHLD);
- X# endif
- X# endif
- X if (ppid == getpid()) { /* Listener process died, or system() bug */
- X# if defined (sequent) || defined (stardent) || defined (stellar) || \
- X defined (titan) || defined (unknown_port)
- X do {
- X pid = wait3 (&status, WNOHANG, NULL);
- X } while (pid && pid != chpid);
- X# else
- X pid = waitpid (chpid, &status, WNOHANG);
- X# endif
- X if (!pid) { /* system() bug */
- X# if defined (bsd)
- X sigsetmask (mask);
- X# elif defined (svr3) || defined (svr4)
- X# ifdef SIGCLD
- X sigrelse (SIGCLD);
- X# else
- X sigrelse (SIGCHLD);
- X# endif
- X# endif
- X signal (sig, (void (*)()) sighandle);
- X return;
- X }
- X }
- X else /* Listener process: "live" child died */
- X pid = wait (&status); /* Get child's pid */
- X for (i = 0; i < nforks; i++) {
- X if (clients [i].pid == pid) { /* Remove dead child's pid */
- X report_progress (report,
- X tsprintf ("Connection closed with %s (client #%d)",
- X clients [i].name, clients [i].connid), TRUE);
- X for (j = i; j < nforks - 1; j++)
- X memcpy ((char *) &clients [j], (char *) &clients [j + 1],
- X sizeof (CLIENT));
- X break;
- X }
- X }
- X if (i == nforks && chpid == getpid())
- X report_progress (report, "Connection closed with last client", TRUE);
- X --nforks;
- X if (WIFSIGNALED (status)) {
- X if (WTERMSIG (status) > SIGINT &&
- X WTERMSIG (status) != ABORT_SIG && WTERMSIG (status) != TIMEOUT_SIG)
- X report_progress (report, tsprintf ("\nsighandle(): Child died \
- Xabnormally: signal %d",
- X WTERMSIG (status)), TRUE);
- X }
- X else if (WIFEXITED (status)) { /* Abnormal child exit status ? */
- X if ((exstatus = WEXITSTATUS (status)) == 0 && pid != chpid) {
- X# if defined (bsd)
- X sigsetmask (mask);
- X# elif defined (svr3) || defined (svr4)
- X# ifdef SIGCLD
- X sigrelse (SIGCLD);
- X# else
- X sigrelse (SIGCHLD);
- X# endif
- X# endif
- X signal (sig, (void (*)()) sighandle);
- X return;
- X }
- X if (exstatus == 6 || exstatus == 7 || exstatus == 8 || exstatus == 11 ||
- X exstatus == 13 || exstatus == 14 || exstatus == 15 || exstatus == 16) {
- X /* Shutdown or restart request, semaphore/socket error */
- X if (exstatus == 7 && ppid == getpid())
- X restart = TRUE; /* Only master process may restart */
- X else if (exstatus == 8)
- X report_progress (report, "\nsighandle(): Child received SIGTERM",
- X TRUE);
- X else if (exstatus == 13 || exstatus == 15) {
- X report_progress (report,
- X tsprintf ("\nsighandle(): Child experienced %s \
- Xerror", (exstatus == 13 ? "socket" : "setuid()/setgid()")), TRUE);
- X# if defined (bsd)
- X sigsetmask (mask);
- X# elif defined (svr3) || defined (svr4)
- X# ifdef SIGCLD
- X sigrelse (SIGCLD);
- X# else
- X sigrelse (SIGCHLD);
- X# endif
- X# endif
- X signal (sig, (void (*)()) sighandle);
- X return;
- X }
- X else if (exstatus == 11 || exstatus == 14 || exstatus == 16)
- X report_progress (report,
- X tsprintf ("\nsighandle(): Child experienced %s\
- X error", ((exstatus == 11 ? "malloc()" :
- X (exstatus == 14 ? "semaphore" : "internal")))), TRUE);
- X if (ppid != getpid()) { /* Master process will exit gracefully */
- X _nforks = nforks; /* As children die nforks decreases */
- X# if defined (bsd)
- X sigsetmask (mask);
- X# elif defined (svr3) || defined (svr4)
- X# ifdef SIGCLD
- X sigrelse (SIGCLD);
- X# else
- X sigrelse (SIGCHLD);
- X# endif
- X# endif
- X signal (sig, (void (*)()) sighandle);
- X for (i = 0; i < _nforks; i++)
- X pids[i] = clients [i].pid;
- X for (i = 0; i < _nforks; i++) /* Kill any "live" children */
- X kill (pids[i], ABORT_SIG);
- X kill (ppid, ABORT_SIG);
- X exit (exstatus);
- X }
- X }
- X }
- X# if defined (bsd)
- X sigsetmask (mask);
- X# elif defined (svr3) || defined (svr4)
- X# ifdef SIGCLD
- X sigrelse (SIGCLD);
- X# else
- X sigrelse (SIGCHLD);
- X# endif
- X# endif
- X signal (sig, (void (*)()) sighandle);
- X if (ppid != getpid()) /* Master process will die */
- X return;
- X else if (pid != chpid) /* Master cares only about the Listener process */
- X return;
- X unlink (PID_SERVERD);
- X }
- X# ifdef SIGCLD
- X signal (SIGCLD, SIG_DFL);
- X# else
- X signal (SIGCHLD, SIG_DFL);
- X# endif
- X if (chpid == getpid()) { /* Listener process */
- X for (i = 0; i < nforks; i++) { /* Kill any "live" children */
- X report_progress (report, tsprintf ("Connection closed with %s (client #%d)",
- X clients [i].name, clients [i].connid),
- X TRUE);
- X kill (clients [i].pid, ABORT_SIG);
- X }
- X while (still_delivering_mail (sid) > 0); /* Wait for list to terminate */
- X kill (ppid, ABORT_SIG); /* Notify master process we are dying */
- X }
- X /* Next two lines are currently useless; kept for future use */
- X if (getpid() != chpid && getpid() != ppid) /* Live process */
- X CLOSE_CLIENT (msg_sock);
- X if (ppid == getpid ())
- X semremove (sid); /* Only master process may remove it */
- X if (restart) {
- X# ifndef NO_LOCKS
- X unlock_file (lfd);
- X# endif
- X execl (START, START, START_OPTIONS, NULL);
- X report_progress (report, "serverd commits suicide: Could not restart system",
- X TRUE);
- X# ifdef SYSLOG
- X closelog ();
- X# else
- X fclose (report);
- X# endif
- X if (sys.options & BSD_MAIL)
- X syscom ("echo '' | %s -s '%s' %s", UCB_MAIL, reply, sys.manager);
- X exit (5);
- X }
- X# ifndef NO_LOCKS
- X unlock_file (lfd);
- X# endif
- X# ifdef SYSLOG
- X closelog ();
- X# else
- X fclose (report);
- X# endif
- X exit (0);
- X}
- X
- X/*
- X Called when Listener process has exited.
- X*/
- X
- Xvoid listener_exited ()
- X{
- X chdied = TRUE;
- X}
- X
- X/*
- X Child has been notified that it should commit suicide, so it does after
- X notifying the client.
- X*/
- X
- Xvoid close_connection (int sig)
- X{
- X char s [256];
- X
- X signal (sig, SIG_IGN);
- X if (sig == TIMEOUT_SIG || sig == SIGALRM)
- X sprintf (s, "%d %d \n%s", CONN_TIMEOUT, strlen (CONN_TIMED_OUT),
- X CONN_TIMED_OUT);
- X else if (sig == SIGTERM)
- X sprintf (s, "%d %d \n%s", CONN_CLOSED, strlen (GOOD_BYE), GOOD_BYE);
- X else if (sig == ABORT_SIG)
- X sprintf (s, "%d %d \n%s", CONN_ABORTED, strlen (SERVER_SHUTS_DOWN),
- X SERVER_SHUTS_DOWN);
- X else
- X sprintf (s, "%d %d \n%s", CONN_ABORTED, strlen (REMOTE_SYS_ERROR),
- X REMOTE_SYS_ERROR);
- X write_to_fd (msg_sock, s, strlen (s));
- X close (msg_sock);
- X# ifndef SYSLOG
- X fclose (report);
- X# endif
- X unlink (requests_file);
- X unlink (mailforwardf);
- X _exit (0);
- X}
- X
- X/*
- X Check whether a child process has been running longer than 'conn_duration'
- X seconds and return its pid, or 0 otherwise.
- X*/
- X
- Xint check_timeout (CLIENT clients [])
- X{
- X int i;
- X
- X for (i = 0; i < nforks; i++)
- X if ((time (0) - clients [i].time) > conn_duration)
- X return clients [i].pid;
- X return 0;
- X}
- X
- X/*
- X Create a socket and bind it to the local address and to an available port.
- X Return the socket file descriptor, or -1 on error.
- X*/
- X
- Xint create_connection ()
- X{
- X struct sockaddr_in server;
- X struct servent *service;
- X struct hostent *hostentry;
- X int sock, timeout = 0, sendbuf = BUFFSIZ, recvbuf = BUFFSIZ, val = 1;
- X
- X# ifndef ILP_PORT
- X if (! (service = getservbyname (SERVICE, NULL))) {
- X report_progress (report, "\ncreate_connection(): Service unavailable",
- X TRUE);
- X return -1;
- X }
- X# endif
- X if (! (hostentry = gethostbyname ("localhost"))) {
- X report_progress (report, "\ncreate_connection(): No such host", TRUE);
- X return -1;
- X }
- X if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
- X report_progress (report, "\ncreate_connection(): Could not create socket",
- X TRUE);
- X return -1;
- X }
- X if (setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *) &sendbuf,
- X sizeof (sendbuf)) < 0)
- X report_progress (report, "\ncreate_connection(): WARNING: Could not \
- Xset send-buffer size: setsockopt() error", TRUE);
- X if (setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &recvbuf,
- X sizeof (recvbuf)) < 0)
- X report_progress (report, "\ncreate_connection(): WARNING: Could not \
- Xset receive-buffer size: setsockopt() error", TRUE);
- X if (setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
- X sizeof (val)) < 0)
- X report_progress (report, "\ncreate_connection():WARNING: Cannot toggle \
- Xkeep-alive connections: setsockopt() error", TRUE);
- X val = 1;
- X if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
- X sizeof (val)) < 0)
- X report_progress (report, "\ncreate_connection():WARNING: Cannot toggle \
- Xreuse of local address: setsockopt() error", TRUE);
- X
- X server.sin_family = AF_INET; /* Internet protocol */
- X server.sin_addr.s_addr = INADDR_ANY;
- X# ifndef ILP_PORT
- X server.sin_port = service->s_port;
- X# else
- X server.sin_port = htons (ILP_PORT);
- X# endif
- X
- X while (bind (sock, (struct sockaddr *) &server, sizeof (server)) < 0 &&
- X errno == EADDRINUSE && timeout < 180) { /* For perm port keep trying */
- X ++timeout;
- X errno = 0;
- X sleep (1);
- X }
- X if (timeout >= 180) {
- X report_progress (report, "\ncreate_connection(): Could not bind", TRUE);
- X return -1;
- X }
- X listen (sock, 5);
- X return sock;
- X}
- X
- X/*
- X Process all live requests coming in from the tcp connection.
- X
- X PLEASE DO NOT MODIFY THIS ROUTINE AS YOU MAY BREAK THE PROTOCOL AND CREATE
- X HAVOC WITH PEER INTERACTIVE LISTPROCESSORS. A LOT OF UNDOCUMENTED
- X ASSUMPTIONS ARE MADE. YOU SHOULD CONTACT ME ABOUT ANY CHANGES YOU WISH TO
- X MAKE.
- X
- X [What a messy routine]
- X*/
- X
- Xvoid process_live_request (int msg_sock, struct sockaddr_in client)
- X{
- X char ch, *buf, *dash, server [MAX_LINE], msg [MAX_LINE], replyf[MAX_LINE];
- X char denied_req [6][MAX_LINE], login [MAX_LINE], *passwd;
- X char *perms [6], *s, *r, *rr;
- X char outfile [MAX_LINE], reply [MAX_LINE], arg [MAX_LINE];
- X char localhost [MAX_LINE], _localhost [MAX_LINE], localaddr [MAX_LINE];
- X char rhost [MAX_LINE], raddr [MAX_LINE];
- X FILE *f;
- X#ifdef ultrix
- X time_t t, time_started;
- X#else
- X long int t, time_started;
- X#endif
- X long int sig_mask, naddr, naddr2, nlines, buffsiz = BUFFSIZ;
- X long int i, j, value, nfds, total_bytes_written = 0, mask;
- X int response, fmode, l, auth = NOTSUBSCRIBED, bytes_read = 0, rcode;
- X int listid, lckmask;
- X BOOLEAN more_input = FALSE, reply_code, bin = TRUE, put_request,
- X already_aborted = TRUE;
- X struct hostent *hp, *rhp;
- X struct stat stat_buf;
- X struct in_addr _addr;
- X
- X sprintf (denied_req [MANAGER], "-d execute -d fax");
- X sprintf (denied_req [OWNER], "%s -d shutdown -d restart",
- X denied_req [MANAGER]);
- X sprintf (denied_req [SUBSCRIBED], "%s -d subscribe -d system -d reports \
- X-d edit -d put -d approve -d discard", denied_req [OWNER]);
- X sprintf (denied_req [NOTSUBSCRIBED], "%s -d unsubscribe -d set -d which \
- X-d run",
- X denied_req [SUBSCRIBED]);
- X perms [MANAGER] = MANAGER_LOGIN;
- X perms [OWNER] = OWNER_LOGIN;
- X perms [SUBSCRIBED] = SUBSCRIBER_LOGIN;
- X perms [NOTSUBSCRIBED] = GENERAL_LOGIN;
- X
- X sprintf (mailforwardf, "%s.%d", TMP_LIVE, getpid());
- X sprintf (replyf, "%s.%d", ULISTPROCESSOR_REPLY, getpid());
- X time_started = time (0);
- X if (gethostname (localhost, sizeof (localhost))) {
- X report_progress (report, tsprintf ("\nprocess_live_request(): gethostname()\
- X failed: errno %d", errno), TRUE);
- X CLIENT_LOST (13);
- X }
- X strcpy (_localhost, localhost);
- X upcase (_localhost);
- X if (write_to_fd (msg_sock, LOGIN, strlen (LOGIN)) < 0)
- X CLIENT_LOST (13);
- X outfile[0] = RESET (login);
- X GET_LOGIN (login);
- X if (!strncmp (login, "__abort__", 9)) /* Client aborted -- Reserved */
- X goto ciao;
- X if (login [0] != EOS) { /* Proceed with authentication */
- X strcpy (msg, login); /* Used to form a "From " line */
- X rr = s = mystrdup (login);
- X upcase (s);
- X while ((s = _strstr (s, "IUL:"))) {
- X s += 4; /* Point to remote host */
- X sscanf (s, "%s", rhost);
- X if ((r = strchr (rhost, ';')))
- X *r = EOS;
- X if (!strcmp (rhost, _localhost)) { /* Loop */
- X sprintf (msg, "Loop detected.\n");
- X REPLY (msg_sock, PEER_UNAVAIL, strlen (msg));
- X write_to_fd (msg_sock, msg, strlen (msg));
- X goto ciao;
- X }
- X rhp = hp = gethostbyname (rhost);
- X if (hp) {
- X if ((rhp = (struct hostent *) malloc (sizeof (struct hostent))) == NULL)
- X report_progress (report, "\nprocess_live_request(): malloc() failed",
- X TRUE),
- X exit (11);
- X memcpy ((char *) rhp, (char *) hp, sizeof (*hp));
- X# ifdef h_addr
- X if ((rhp->h_addr_list = (char **) malloc (sizeof (char *))) == NULL)
- X report_progress (report, "\nprocess_live_request(): malloc() failed",
- X TRUE),
- X exit (11);
- X naddr = 0;
- X while (hp->h_addr_list[naddr]) {
- X if ((rhp->h_addr_list = (char **)
- X realloc (rhp->h_addr_list, (naddr + 2) * sizeof (char *))) ==
- X NULL)
- X report_progress (report,
- X "\nprocess_live_request(): realloc() failed", TRUE),
- X exit (11);
- X if ((rhp->h_addr_list[naddr] = (char *)
- X malloc (rhp->h_length * sizeof (char))) == NULL)
- X report_progress (report,
- X "\nprocess_live_request(): malloc() failed", TRUE),
- X exit (11);
- X memcpy ((char *) rhp->h_addr_list[naddr],
- X (char *) hp->h_addr_list[naddr], hp->h_length);
- X rhp->h_addr_list[++naddr] = NULL;
- X }
- X naddr = 0;
- X while (rhp->h_addr_list[naddr]) {
- X memcpy ((char *) &_addr, (char *) rhp->h_addr_list[naddr++],
- X rhp->h_length);
- X strcpy (raddr, (char *) inet_ntoa (_addr));
- X hp = gethostbyname (localhost);
- X naddr2 = 0;
- X while (hp && hp->h_addr_list[naddr2]) {
- X memcpy ((char *) &_addr, (char *) hp->h_addr_list[naddr2++],
- X hp->h_length);
- X strcpy (localaddr, (char *) inet_ntoa (_addr));
- X if (!strcmp (raddr, localaddr)) { /* Loop */
- X sprintf (msg, "Loop detected.\n");
- X REPLY (msg_sock, PEER_UNAVAIL, strlen (msg));
- X write_to_fd (msg_sock, msg, strlen (msg));
- X goto ciao;
- X }
- X }
- X }
- X naddr = 0;
- X while (rhp->h_addr_list[naddr])
- X free ((char *) rhp->h_addr_list[naddr++]);
- X free ((char **) rhp->h_addr_list);
- X# else
- X if ((rhp->h_addr = (char *) malloc ((strlen (hp->h_addr) + 1) *
- X sizeof (char))) == NULL)
- X report_progress (report, "\nprocess_live_request(): malloc() failed",
- X TRUE),
- X exit (11);
- X memcpy ((char *) rhp->h_addr, (char *) hp->h_addr, hp->h_length);
- X memcpy ((char *) &_addr, (char *) rhp->h_addr, rhp->h_length);
- X strcpy (raddr, (char *) inet_ntoa (_addr));
- X hp = gethostbyname (rhost);
- X memcpy ((char *) &_addr, (char *) hp->h_addr, hp->h_length);
- X strcpy (localaddr, (char *) inet_ntoa (_addr));
- X if (!strcmp (raddr, localaddr)) { /* Loop */
- X sprintf (msg, "Loop detected.\n");
- X REPLY (msg_sock, PEER_UNAVAIL, strlen (msg));
- X write_to_fd (msg_sock, msg, strlen (msg));
- X goto ciao;
- X }
- X free ((char *) rhp->h_addr);
- X# endif
- X free ((struct hostent *) rhp);
- X }
- X hp = gethostbyname (localhost);
- X naddr = 0;
- X# ifdef h_addr
- X while (hp && hp->h_addr_list[naddr]) {
- X memcpy ((char *) &_addr, (char *) hp->h_addr_list[naddr++],
- X hp->h_length);
- X strcpy (localaddr, (char *) inet_ntoa (_addr));
- X if (!strcmp (rhost, localaddr)) { /* Loop */
- X sprintf (msg, "Loop detected.\n");
- X REPLY (msg_sock, PEER_UNAVAIL, strlen (msg));
- X write_to_fd (msg_sock, msg, strlen (msg));
- X goto ciao;
- X }
- X }
- X# else
- X memcpy ((char *) &_addr, (char *) hp->h_addr, hp->h_length);
- X strcpy (localaddr, (char *) inet_ntoa (_addr));
- X if (!strcmp (rhost, localaddr)) { /* Loop */
- X sprintf (msg, "Loop detected.\n");
- X REPLY (msg_sock, PEER_UNAVAIL, strlen (msg));
- X write_to_fd (msg_sock, msg, strlen (msg));
- X goto ciao;
- X }
- X# endif
- X }
- X free ((char *) rr);
- X REPLY (msg_sock, PASSWORD_REQUIRED, strlen (PASSWORD));
- X if (write_to_fd (msg_sock, PASSWORD, strlen (PASSWORD)) < 0)
- X CLIENT_LOST (13);
- X if ((passwd = (char *) malloc (MAX_LINE * sizeof (char))) == NULL)
- X report_progress (report,
- X "\nprocess_live_request(): malloc() failed", TRUE),
- X exit (11);
- X RESET (passwd);
- X GET_LOGIN (passwd);
- X if (!strncmp (passwd, "__abort__", 9)) /* Client aborted -- Reserved */
- X goto ciao;
- X upcase (passwd);
- X if (!strcmp (login, sys.manager)) /* Check to see if he's the manager */
- X if (!strcmp (passwd, sys.server.password)) {
- X auth = MANAGER;
- X REPLY (msg_sock, OK, strlen (perms [auth]) + strlen (PROMPT));
- X if (write_to_fd (msg_sock, perms [auth], strlen (perms [auth])) < 0)
- X CLIENT_LOST (13);
- X goto skip;
- X }
- X upcase (login);
- X for (listid = 0; listid < nlists; listid++) /* Check to see if he is an owner */
- X if (owner_listed (OWNERSF, login, sys.lists[listid].alias, report) ==
- X OWNER)
- X if (!strcmp (passwd, sys.lists[listid].password)) {
- X auth = OWNER;
- X REPLY (msg_sock, OK, strlen (perms [auth]) + strlen (PROMPT));
- X if (write_to_fd (msg_sock, perms [auth], strlen (perms [auth])) < 0)
- X CLIENT_LOST (13);
- X goto skip;
- X }
- X
- X for (listid = 0; listid < nlists; listid++) { /* Check for regular subscription */
- X setup_string (subscribersf, sys.lists[listid].alias, SUBSCRIBERS);
- X sprintf (password_in_sub_file, "%ld", time (0));
- X if (subscribed (report, login, subscribersf, NULL, NULL, NULL, TRUE) ==
- X SUBSCRIBED)
- X if (!strcmp (passwd, password_in_sub_file)) {
- X auth = SUBSCRIBED;
- X REPLY (msg_sock, OK, strlen (perms [auth]) + strlen (PROMPT));
- X if (write_to_fd (msg_sock, perms [auth], strlen (perms [auth])) < 0)
- X CLIENT_LOST (13);
- X goto skip;
- X }
- X }
- X }
- X else
- X REPLY (msg_sock, OK, 0);
- X REPLY (msg_sock, OK, strlen (perms [auth]) + strlen (PROMPT));
- X if (write_to_fd (msg_sock, perms [auth], strlen (perms [auth])) < 0)
- X CLIENT_LOST (13);
- X hp = gethostbyaddr ((char *) &client.sin_addr,
- X sizeof (struct in_addr), client.sin_family);
- X sprintf (msg, "IUL:%s;%s",
- X (hp ? hp->h_name : (char *) inet_ntoa (client.sin_addr)),
- X login);
- X
- X skip:
- X hp = gethostbyaddr ((char *) &client.sin_addr,
- X sizeof (struct in_addr), client.sin_family);
- X if (write_to_fd (msg_sock, PROMPT, strlen (PROMPT)) < 0)
- X CLIENT_LOST (13);
- X
- X if ((buf = (char *) malloc (buffsiz * sizeof (char))) == NULL)
- X report_progress (report,
- X "\nprocess_live_request(): malloc() failed", TRUE),
- X exit (11);
- X
- X ch = RESET (buf);
- X
- X while (ch != EOF && bytes_read < MAX_LINE) { /* Get request & process it */
- X errno = 0;
- X if (read (msg_sock, &ch, 1) <= 0) {
- X if (errno == EINTR
- X# ifdef ERESTART
- X || errno == ERESTART
- X# endif
- X )
- X continue;
- X break;
- X }
- X if (time (0) - time_started > conn_duration) /* In case SIGALRM f_cks up */
- X close_connection (TIMEOUT_SIG);
- X ++bytes_read;
- X if (ch >= ' ' || (isspace (ch) && ch != '\r') || ch == '\03') {
- X# ifndef NO_ABORT_OP
- X if (ch == '\03') {
- X if (!already_aborted) {
- X sprintf (urgmsg, "%08ld", total_bytes_written);
- X SEND_OOB_BYTE;
- X SEND_MSG;
- X REPLY (msg_sock, OK, strlen (PROMPT));
- X if (write_to_fd (msg_sock, PROMPT, strlen (PROMPT)) < 0)
- X CLIENT_LOST (13);
- X }
- X continue;
- X }
- X# endif
- X if (ch != '\n') /* Buffer request */
- X buf [(l = strlen (buf))] = ch,
- X buf [l + 1] = EOS;
- X else { /* End of request? process it */
- X if (strlen (buf) && buf [strlen (buf) - 1] == '&') { /* Request continues */
- X buf [strlen (buf) - 1] = EOS; /* Replace & */
- X REPLY (msg_sock, CONTINUED, strlen (CONT_PROMPT));
- X if (write_to_fd (msg_sock, CONT_PROMPT, strlen (CONT_PROMPT)) < 0)
- X CLIENT_LOST (13);
- X continue;
- X }
- X if (!more_input) {
- X clean_request (buf);
- X if (!strncmp (buf, "quit", 4) || !strncmp (buf, "exit", 4))
- X break;
- X if (!strncmp (buf, "__abort__", 9)) /* Reserved */
- X goto ciao;
- X# ifdef bsd
- X sig_mask = sigblock (sigmask (SIGALRM) | sigmask (TIMEOUT_SIG));
- X# elif defined (svr4) || defined (svr3)
- X sighold (SIGALRM);
- X sighold (TIMEOUT_SIG);
- X# endif
- X if (!strncmp (buf, "binary", 3)) {
- X bin = TRUE;
- X REPLY (msg_sock, OK, strlen (BINARY_XFER) + strlen (PROMPT));
- X if (write_to_fd (msg_sock, BINARY_XFER, strlen (BINARY_XFER)) < 0)
- X CLIENT_LOST (13);
- X goto Skip;
- X }
- X if (!strncmp (buf, "ascii", 3)) {
- X bin = FALSE;
- X REPLY (msg_sock, OK, strlen (ASCII_XFER) + strlen (PROMPT));
- X if (write_to_fd (msg_sock, ASCII_XFER, strlen (ASCII_XFER)) < 0)
- X CLIENT_LOST (13);
- X goto Skip;
- X }
- X if (buf [0] == '?' || !strncmp (buf, "privileges", 4)) {
- X REPLY (msg_sock, OK, strlen (perms [auth]) + strlen (PROMPT));
- X if (write_to_fd (msg_sock, perms [auth], strlen (perms [auth])) < 0)
- X CLIENT_LOST (13);
- X goto Skip;
- X }
- X if (!strncmp (buf, "timeleft", 4)) {
- X sprintf (buf, "Time left: %d seconds\n", conn_duration - time (0) +
- X time_started);
- X REPLY (msg_sock, OK, strlen (buf) + strlen (PROMPT));
- X if (write_to_fd (msg_sock, buf, strlen (buf)) < 0)
- X CLIENT_LOST (13);
- X goto Skip;
- X }
- X
- X sprintf (requests_file, "%s.r%d", TMP_LIVE, getpid());
- X OPEN_FILE (f, requests_file, "w", "process_live_request");
- X chown (requests_file, pwentry->pw_uid, pwentry->pw_gid);
- X t = time (0);
- X fprintf (f, "From %s %sComment: ILP connection from %s\nAccess: ",
- X msg, ctime (&t),
- X (hp ? hp->h_name : (char *) inet_ntoa (client.sin_addr)));
- X if (auth == SUBSCRIBED)
- X fprintf (f, "Subscriber to list %s", sys.lists[listid].alias);
- X else if (auth == OWNER)
- X fprintf (f, "Owner of list %s", sys.lists[listid].alias);
- X else if (auth == MANAGER)
- X fprintf (f, "Manager");
- X else
- X fprintf (f, "Casual");
- X fprintf (f, "\n\n");
- X
- X put_request = FALSE;
- X RESET (arg);
- X sscanf (buf, "%s", arg);
- X if (re_strcmp ("^PUT$|^PUT[ \t]", upcase (arg), NULL) > 0) {
- X if (!check_for_redirection (buf, outfile, &fmode, msg_sock, bin)) {
- X fclose (f);
- X goto Skip;
- X }
- X if (outfile [0] != EOS &&
- X !writeable_file (outfile, msg_sock)) {
- X fclose (f);
- X goto Skip;
- X }
- X REPLY (msg_sock, MORE_INPUT_REQUIRED, strlen (MORE_INPUT));
- X if (write_to_fd (msg_sock, MORE_INPUT, strlen (MORE_INPUT)) < 0)
- X CLIENT_LOST (13);
- X more_input = TRUE;
- X reply_code = FALSE;
- X put_request = TRUE;
- X if (auth >= SUBSCRIBED && (dash = _strstr (buf, " - ")))
- X insert_word (dash + 1, &passwd, 1, 0, 1);
- X }
- X }
- X
- X if (!strcmp (buf, ".") && more_input)
- X more_input = FALSE;
- X if (!strncmp (buf, "..", 2) && more_input) /* Remove one dot */
- X for (l = 0; l < strlen (buf); l++)
- X buf [l] = buf [l + 1];
- X
- X if (more_input && ch == '\n' && buf[0] == EOS)
- X strcat (buf, " "); /* Kludge */
- X
- X if (buf[0] != EOS) { /* Not \n only */
- X
- X if (!more_input) {
- X if (!put_request) { /* Redirection has been checked and verified */
- X if (!check_for_redirection (buf, outfile, &fmode, msg_sock, bin)) {
- X fclose (f);
- X goto Skip;
- X }
- X RESET (arg);
- X sscanf (buf, "%s", arg);
- X if (outfile [0] != EOS || !strcmp (upcase (arg), "GET")) {
- X if (outfile [0] == EOS && !strcmp (arg, "GET"))
- X sscanf (buf, "%s %s %s", arg, arg, outfile),
- X fmode = (bin ? WRITE_TO_FILE_BIN : WRITE_TO_FILE_ASC);
- X if (!writeable_file (outfile, msg_sock)) {
- X fclose (f);
- X goto Skip;
- X }
- X }
- X }
- X if (strcmp (buf, ".")) {
- X if (auth >= SUBSCRIBED && (dash = _strstr (buf, " - ")))
- X insert_word (dash + 1, &passwd, 1, 0, 1);
- X fprintf (f, "%s\n", buf);
- X }
- X fclose (f);
- X
- X sscanf (buf, "%s", arg);
- X upcase (arg);
- X lckmask = SEM_REQ_ID;
- X if (!strncmp (arg, "SET", 3) || !strncmp (arg, "UNS", 3) ||
- X !strncmp (arg, "REC", 3) || !strncmp (arg, "REV", 3) ||
- X !strncmp (arg, "INF", 3) || !strncmp (arg, "STA", 3) ||
- X !strncmp (arg, "WHI", 3) || !strncmp (arg, "REP", 3) ||
- X !strncmp (arg, "EDI", 3) || !strncmp (arg, "PUT", 3) ||
- X !strncmp (arg, "SYS", 3))
- X lckmask |= SEM_LISTFILES;
- X else if (!strncmp (arg, "IND", 3) || !strncmp (arg, "GET", 3) ||
- X !strncmp (arg, "SEA", 3) || !strncmp (arg, "VIE", 3))
- X lckmask |= SEM_ARCHIVES;
- X else if (!strncmp (arg, "SHU", 3) || !strncmp (arg, "RES", 3))
- X lckmask |= SEM_DLVR_MAIL;
- X CHECK_CRITICAL_SECTION ("process_live_request", msg_sock, lckmask);
- X
- X sprintf (server, "%s -i %s %s -S %d -F %s -R %s -C %s", SERVER,
- X sys.server.cmdoptions, denied_req [auth], sid,
- X mailforwardf, requests_file, replyf);
- X run_program (server, TRUE, msg_sock);
- X unlink (requests_file);
- X if ((f = fopen (replyf, "r")) != NULL)
- X fscanf (f, "%d", &rcode),
- X fclose (f);
- X else
- X rcode = SYS_ERROR;
- X# ifndef NO_ABORT_OP
- X already_aborted = FALSE;
- X SET_NONBLOCKING ("process_live_request");
- X errno = 0;
- X if ((value = recv (msg_sock, &ch, 1, MSG_OOB)) > 0)
- X if (ch == '\03') {
- X strcat (urgmsg, "00000000");
- X SET_BLOCKING ("process_live_request");
- X SEND_OOB_BYTE;
- X SEND_MSG;
- X already_aborted = TRUE;
- X REPLY (msg_sock, OK, strlen (PROMPT));
- X goto Skip;
- X }
- X else
- X report_progress (report,
- X tsprintf ("\nprocess_live_request(): \
- Xrecv(): unexpected char %c", ch), TRUE);
- X else if (value < 0 && errno && errno != EWOULDBLOCK &&
- X errno != EAGAIN && errno != EINTR && errno != EINVAL)
- X report_progress (report,
- X tsprintf ("\nprocess_live_request(): \
- Xrecv() failed: errno %d", errno), TRUE);
- X
- X SET_BLOCKING ("process_live_request");
- X# endif
- X if ((response = open (mailforwardf, O_RDONLY)) >= 0) {
- X stat (mailforwardf, &stat_buf);
- X nlines = 0;
- X if (outfile [0] != EOS &&
- X (rcode == WRITE_TO_FILE_ASC || rcode == WRITE_TO_FILE_BIN ||
- X rcode == OK || rcode == RESTRICTED_REQ ||
- X rcode == PERMISSION_DENIED)) {
- X if (!bin) { /* Count # of \n chars */
- X bytes_read = 1;
- X while (bytes_read > 0) {
- X errno = 0;
- X while ((bytes_read = read (response, buf, BUFFSIZ - 1)) < 0
- X && (errno == EINTR
- X# ifdef ERESTART
- X || errno == ERESTART)
- X# else
- X )
- X# endif
- X )
- X errno = 0;
- X if (errno && errno != EINTR
- X# ifdef ERESTART
- X && errno != ERESTART
- X# endif
- X ) {
- X unlink (mailforwardf);
- X CLOSE_CLIENT (msg_sock);
- X# ifndef SYSLOG
- X fclose (report);
- X# endif
- X
- X _exit (13);
- X }
- X for (i = 0; i < bytes_read; ++i)
- X if (buf[i] == '\n') ++nlines;
- X }
- X lseek (response, 0L, SEEK_SET);
- X }
- X REPLY_FILE (msg_sock, fmode,
- X stat_buf.st_size + strlen (PROMPT) + nlines,
- X outfile)
- X }
- X else
- X REPLY (msg_sock, rcode, stat_buf.st_size + strlen (PROMPT));
- X bytes_read = 1;
- X total_bytes_written = 0;
- X while (bytes_read > 0) {
- X errno = 0;
- X while ((bytes_read = read (response, buf, BUFFSIZ)) < 0
- X && (errno == EINTR
- X# ifdef ERESTART
- X || errno == ERESTART)
- X# else
- X )
- X# endif
- X )
- X errno = 0;
- X if (errno && errno != EINTR
- X# ifdef ERESTART
- X && errno != ERESTART
- X# endif
- X ) {
- X unlink (mailforwardf);
- X CLOSE_CLIENT (msg_sock);
- X# ifndef SYSLOG
- X fclose (report);
- X# endif
- X _exit (13);
- X }
- X if (bytes_read > 0) {
- X if (!bin && outfile[0] != EOS &&
- X (rcode == WRITE_TO_FILE_ASC ||
- X rcode == WRITE_TO_FILE_BIN ||
- X rcode == OK || rcode == RESTRICTED_REQ ||
- X rcode == PERMISSION_DENIED))
- X for (i = 0; i < bytes_read; i++)
- X if (buf [i] == '\n') {
- X if (bytes_read == buffsiz)
- X if ((buf = (char *)
- X realloc (buf, (++buffsiz) * sizeof (char))) ==
- X NULL) {
- X unlink (mailforwardf);
- X report_progress (report, "\nprocess_live_request():\
- X realloc() failed", TRUE),
- X exit (11);
- X }
- X for (j = bytes_read; j > i; j--)
- X buf [j] = buf [j - 1];
- X buf [i] = '\r';
- X ++bytes_read;
- X ++i;
- X }
- X if ((value = write_to_fd (msg_sock, buf, bytes_read)) < 0) {
- X unlink (mailforwardf);
- X CLIENT_LOST (13);
- X }
- X total_bytes_written += value;
- X# ifndef NO_ABORT_OP
- X SET_NONBLOCKING ("process_live_request");
- X errno = 0;
- X if ((value = recv (msg_sock, &ch, 1, MSG_OOB)) > 0)
- X if (ch == '\03') {
- X sprintf (urgmsg, "%08ld", total_bytes_written);
- X SET_BLOCKING ("process_live_request");
- X SEND_OOB_BYTE;
- X SEND_MSG;
- X already_aborted = TRUE;
- X REPLY (msg_sock, OK, strlen (PROMPT));
- X break;
- X }
- X else
- X report_progress (report,
- X tsprintf ("\nprocess_live_request(): \
- Xrecv(): unexpected char %c", ch), TRUE);
- X else if (value < 0 && errno && errno != EWOULDBLOCK &&
- X errno != EAGAIN && errno != EINTR && errno != EINVAL)
- X report_progress (report,
- X tsprintf ("\nprocess_live_request(): \
- Xrecv() failed: errno %d", errno), TRUE);
- X SET_BLOCKING ("process_live_request");
- X# endif
- X }
- X }
- X close (response);
- X }
- X else
- X REPLY_ERROR (msg_sock, SYS_ERROR, strlen (REMOTE_SYS_ERROR) +
- X strlen (PROMPT), REMOTE_SYS_ERROR);
- X RESET (outfile);
- X }
- X else { /* More input */
- X fprintf (f, "%s\n", buf);
- X if (reply_code) /* Kludge */
- X REPLY (msg_sock, OK, 0);
- X reply_code = TRUE;
- X }
- X }
- X else { /* Empty request */
- X fclose (f);
- X REPLY (msg_sock, OK, strlen (PROMPT));
- X }
- X Skip:
- X unlink (mailforwardf);
- X unlink (replyf);
- X if (!more_input)
- X if (write_to_fd (msg_sock, PROMPT, strlen (PROMPT)) < 0)
- X CLIENT_LOST (13);
- X bytes_read = 0;
- X ch = RESET (buf);
- X# ifndef NO_ABORT_OP
- X SET_NONBLOCKING ("process_live_request");
- X errno = 0;
- X if ((value = recv (msg_sock, &ch, 1, MSG_OOB)) > 0)
- X if (ch == '\03') {
- X sprintf (urgmsg, "%08ld", total_bytes_written);
- X SET_BLOCKING ("process_live_request");
- X SEND_OOB_BYTE;
- X SEND_MSG;
- X already_aborted = TRUE;
- X REPLY (msg_sock, OK, strlen (PROMPT));
- X if (write_to_fd (msg_sock, PROMPT, strlen (PROMPT)) < 0)
- X CLIENT_LOST (13);
- X }
- X else
- X report_progress (report,
- X tsprintf ("\nprocess_live_request(): \
- Xrecv(): unexpected char %c", ch), TRUE);
- X else if (value < 0 && errno && errno != EWOULDBLOCK &&
- X errno != EAGAIN && errno != EINTR && errno != EINVAL)
- X report_progress (report,
- X tsprintf ("\nprocess_live_request(): \
- Xrecv() failed: errno %d", errno), TRUE);
- X while (recv (msg_sock, &ch, 1, MSG_OOB) > 0);
- X SET_BLOCKING ("process_live_request");
- X# endif
- X# ifdef bsd
- X sigsetmask (sig_mask);
- X# elif defined (svr4) || defined (svr3)
- X sigrelse (SIGALRM);
- X sigrelse (TIMEOUT_SIG);
- X# endif
- X }
- X }
- X }
- X abort:
- X REPLY (msg_sock, CONN_CLOSED, strlen (GOOD_BYE));
- X write_to_fd (msg_sock, GOOD_BYE, strlen (GOOD_BYE));
- X ciao:
- X free ((char *) buf);
- X free ((char *) passwd);
- X unlink (mailforwardf);
- X unlink (replyf);
- X unlink (requests_file);
- X close (msg_sock);
- X# ifndef SYSLOG
- X fclose (report);
- X# endif
- X _exit (0);
- X}
- X
- X/*
- X Check for redirection to a file; return TRUE if no errors, FALSE otherwise.
- X The file to written to (if any) will be stored in 'outfile' and 'fmode'
- X will be set.
- X*/
- X
- XBOOLEAN check_for_redirection (char *buf, char *outfile, int *fmode,
- X int msg_sock, BOOLEAN bin)
- X{
- X char *s = buf, *b = buf, *r, reply [MAX_LINE];
- X int i, nquote = 0, nch;
- X extern int literal;
- X
- X RESET (outfile);
- X *fmode = 0;
- X while (*s != EOS) {
- X prevch (s, b);
- X if (!nquote) {
- X if (literal)
- X *(s - 1) = *s,
- X *s = (char) 0x1;
- X else if (*s == '\'')
- X nquote = 1;
- X else if (*s == '"')
- X nquote = 2;
- X else if (*s == '>') {
- X if (!literal && outfile[0] == EOS) {
- X nch = nextch (s);
- X sscanf (s + (nch != '>' ? 1 : 2), "%s", outfile);
- X if (outfile [0] == EOS) {
- X REPLY (msg_sock, SYNTAX_ERROR, strlen (NULL_REDIRECT) +
- X strlen (PROMPT));
- X if (write_to_fd (msg_sock, NULL_REDIRECT, strlen (NULL_REDIRECT)) < 0)
- X CLIENT_LOST (13);
- X return FALSE;
- X }
- X else {
- X *fmode = (bin ? WRITE_TO_FILE_BIN : WRITE_TO_FILE_ASC);
- X if (nch == '>')
- X *fmode = (bin ? APPEND_TO_FILE_BIN : APPEND_TO_FILE_ASC);
- X r = s + 1; /* Remove > or >> and file name */
- X if (nch == '>') ++r;
- X while (*r != EOS && (*r == ' ' || *r == '\t')) ++r;
- X while (*r != EOS && !isspace (*r)) ++r;
- X sprintf (s, "%s", r);
- X --s;
- X }
- X }
- X }
- X }
- X else if ((nquote == 1 && *s == '\'') ||
- X (nquote == 2 && *s == '"')) {
- X if (!literal)
- X nquote = 0;
- X else
- X *(s - 1) = *s,
- X *s = (char) 0x1;
- X }
- X ++s;
- X }
- X for (s = buf; *s != EOS; ++s)
- X if (*s == 0x1)
- X sprintf (s, "%s", s + 1),
- X --s;
- X return TRUE;
- X}
- X
- X/*
- X Return TRUE if the file is writeable on the client side, FALSE otherwise.
- X*/
- X
- XBOOLEAN writeable_file (char *outfile, int msg_sock)
- X{
- X char reply [MAX_LINE];
- X int i = 0, err;
- X
- X REPLY_FILE (msg_sock, TEST_FILE_PERMISSIONS, 0, outfile);
- X errno = 0;
- X while (read (msg_sock, reply, 3) < 0 && (errno == EINTR
- X# ifdef ERESTART
- X || errno == ERESTART)
- X# else
- X )
- X# endif
- X ) {
- X i = sizeof (err);
- X if (!getsockopt (sock_fd, SOL_SOCKET, SO_ERROR, (char *) &err, (int *) &i)) {
- X if (err)
- X CLIENT_LOST (13);
- X }
- X else {
- X REPLY (msg_sock, SYS_ERROR, strlen (REMOTE_SYS_ERROR));
- X write_to_fd (msg_sock, REMOTE_SYS_ERROR, strlen (REMOTE_SYS_ERROR));
- X CLIENT_LOST (13);
- X }
- X errno = 0;
- X }
- X if (errno && errno != EINTR
- X# ifdef ERESTART
- X && errno != ERESTART
- X# endif
- X ) {
- X CLIENT_LOST (13);
- X }
- X reply [3] = EOS;
- X if (atoi (reply) == PERMISSION_DENIED) {
- X REPLY (msg_sock, OK, strlen (PROMPT));
- X RESET (outfile);
- X return FALSE;
- X }
- X return TRUE;
- X}
- X
- X/*
- X Return TRUE id 'pid' in in 'clients', FALSE otherwise.
- X*/
- X
- XBOOLEAN child_alive (int pid, CLIENT clients [])
- X{
- X int i;
- X
- X for (i = 0; i < nforks; i++)
- X if (clients[i].pid == pid)
- X return TRUE;
- X return FALSE;
- X}
- X
- X/*
- X Return TRUE if we are currently delivering mail, FALSE otherwise.
- X*/
- X
- XBOOLEAN still_delivering_mail (int sid)
- X{
- X int i = semctl (sid, 0, GETVAL);
- X
- X return ((i >= 0 ? i : 0) & SEM_DLVR_MAIL);
- X}
- X#endif
- *-*-END-of-src/serverd.c-*-*
- echo x - src/signals.c
- sed 's/^X//' >src/signals.c <<'*-*-END-of-src/signals.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | SIGNAL FUNCTIONS |
- X | |
- X | Version 2.2 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X*/
- X
- X#include <stdio.h>
- X#include <signal.h>
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include "defs.h"
- X#include "struct.h"
- X
- X#include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X
- X#ifdef GO_INTERACTIVE
- X# include <sys/types.h>
- X# include <sys/ipc.h>
- X# include <sys/sem.h>
- X#endif
- X
- X#ifdef __STDC__
- X# include <stdarg.h>
- Xextern int syscom (char *, ...);
- Xextern char *tsprintf (char *, ...);
- X#else
- X# include <varargs.h>
- Xextern int syscom ();
- Xextern char *tsprintf ();
- X#endif
- Xextern void report_progress (FILE *, char *, int);
- Xextern char *extract_filename (char *);
- Xextern int gexit (int);
- X
- Xvoid init_signals (void);
- Xvoid catch_signals (void);
- Xvoid my_abort (int);
- X
- Xstatic char *signals[MAX_SIGNAL + 1]; /* Signal names */
- X
- X/*
- X Initialize the signals[].
- X*/
- X
- Xvoid init_signals ()
- X{
- X signals[SIGILL] = "SIGILL";
- X signals[SIGQUIT] = "SIGQUIT";
- X signals[SIGTERM] = "SIGTERM";
- X#ifdef SIGBUS
- X signals[SIGBUS] = "SIGBUS";
- X#endif
- X signals[SIGSEGV] = "SIGSEGV";
- X signals[SIGKILL] = "SIGKILL";
- X}
- X
- X/*
- X Catch signals to print messages before aborting.
- X*/
- X
- Xvoid catch_signals ()
- X{
- X#ifdef _AIX
- X struct sigaction s;
- X#endif
- X
- X#ifdef SIGTSTP
- X signal (SIGTSTP, SIG_IGN);
- X#endif
- X#ifdef SIGTTIN
- X signal (SIGTTIN, SIG_IGN);
- X#endif
- X#ifdef SIGTTOU
- X signal (SIGTTOU, SIG_IGN);
- X#endif
- X signal (SIGHUP, SIG_IGN);
- X signal (SIGILL, my_abort);
- X signal (SIGQUIT, my_abort);
- X signal (SIGTERM, my_abort);
- X signal (SIGSEGV, my_abort);
- X#ifdef SIGBUS
- X signal (SIGBUS, my_abort);
- X#endif
- X signal (SIGKILL, my_abort); /* Can't be caught, but why not try? */
- X#ifdef _AIX
- X s.sa_handler = my_abort;
- X s.sa_mask.losigs = s.sa_mask.hisigs = 0;
- X s.sa_flags = SA_FULLDUMP;
- X sigaction (SIGSEGV, &s, (struct sigaction *) NULL);
- X sigaction (SIGILL, &s, (struct sigaction *) NULL);
- X sigaction (SIGQUIT, &s, (struct sigaction *) NULL);
- X sigaction (SIGBUS, &s, (struct sigaction *) NULL);
- X#endif
- X}
- X
- X/*
- X Kill program after sending message to MANAGER that this is
- X about to happen (message is sent only when using UCB mail).
- X*/
- X
- Xvoid my_abort (int sig)
- X{
- X extern SYS sys;
- X extern char *prog;
- X extern FILE *report;
- X extern int sid;
- X char *s;
- X
- X signal (sig, SIG_IGN);
- X report_progress (report, tsprintf ("\n*** %s: Received %s signal ***\n",
- X (prog ? prog : "???"),
- X signals[sig]), -TRUE);
- X if (sys.options & BSD_MAIL)
- X syscom ("echo '' | %s -s '%s received %s' %s &", UCB_MAIL,
- X (prog ? prog : "???"), signals[sig], sys.manager);
- X if (sig == SIGQUIT || sig == SIGILL || sig == SIGSEGV
- X#ifdef SIGBUS
- X || sig == SIGBUS
- X#endif
- X ) {
- X#ifdef GO_INTERACTIVE
- X union semun {
- X int val;
- X struct semid_ds *buf;
- X ushort *array;
- X } sembuf;
- X sembuf.val = 0;
- X /* Reset flag so that serverd will not wait for ever. */
- X if (sid >= 0 && semctl (sid, 0, SETVAL, sembuf) < 0)
- X report_progress (report, tsprintf ("\ngexit(): Error semctl(); errno %d",
- X errno), TRUE);
- X#endif
- X if (prog)
- X s = extract_filename (prog),
- X#ifdef __STDC__
- X syscom ("rm -f %s/core; touch %s/core.%s; ln -s %s/core.%s %s/core",
- X PATH, PATH, s, PATH, s, PATH),
- X#else
- X syscom ("rm -f %s/core; touch %s/core.%s; ln -s %s/core.%s %s/core",
- X PATH", PATH", s, PATH", s, PATH"),
- X#endif
- X abort ();
- X }
- X gexit (8);
- X}
- *-*-END-of-src/signals.c-*-*
- echo x - src/silp.c
- sed 's/^X//' >src/silp.c <<'*-*-END-of-src/silp.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | SYSTEM INTERACTIVE LISTPROCESSOR CLIENT |
- X | |
- X | Version 1.1 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X This is a copy of the ilp client (ilp.c) ported for internal use by listproc
- X for connections to remote servers while processing requests for remote lists.
- X
- X Refer to the man page (ilp.1) or ilp.c for more information.
- X
- X PLEASE DO NOT MODIFY THESE ROUTINES AS YOU MAY BREAK THE PROTOCOL AND CREATE
- X HAVOC WITH PEER INTERACTIVE LISTPROCESSORS. A LOT OF UNDOCUMENTED
- X ASSUMPTIONS ARE MADE. YOU SHOULD CONTACT ME ABOUT ANY CHANGES YOU WISH TO
- X MAKE.
- X*/
- X
- X#include <signal.h>
- X#include "defs.h"
- X#undef NSIG
- X#ifdef GO_INTERACTIVE
- X# include <stdio.h>
- X# include <sys/types.h>
- X# include <string.h>
- X# if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
- X && !defined (sequent) && !defined (unknown_port)
- X# include <malloc.h>
- X# endif
- X# ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X# endif
- X# if defined (stardent) || defined (stellar) || defined (titan)
- X# include <rpc/types.h>
- X# endif
- X# include <sys/stat.h>
- X# include <fcntl.h>
- X# include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X# include <sys/socket.h>
- X# include <netinet/in.h>
- X# include <netdb.h>
- X# include <sys/file.h>
- X# include <sys/ioctl.h>
- X# if defined (sco) || defined (M_XENIX) || defined (M_UNIX)
- X# include <sys/stropts.h>
- X# endif
- X# if (defined (sco) || defined (M_XENIX) || defined (M_UNIX)) && \
- X defined (HAVE_SELECT_H)
- X# include <sys/times.h>
- X# else
- X# include <sys/time.h>
- X# endif
- X# ifdef HAVE_SETJMP_H
- X# include <setjmp.h>
- X# endif
- X# ifdef HAVE_SELECT_H
- X# include <sys/select.h>
- X# endif
- X# ifdef HAVE_ULIMIT_H
- X# include <ulimit.h>
- X# endif
- X# include "ilp.h"
- X
- X# ifndef UL_GDESLIM
- X# define UL_GDESLIM 4
- X# endif
- X
- X# ifndef FD_SET /* for 4.2BSD */
- X# define FD_SETSIZE (sizeof(fd_set) * 8)
- X# define FD_SET(n, p) (((fd_set *) (p))->fds_bits[0] |= (1 << ((n) % 32)))
- X# define FD_CLR(n, p) (((fd_set *) (p))->fds_bits[0] &= ~(1 << ((n) % 32)))
- X# define FD_ISSET(n, p) (((fd_set *) (p))->fds_bits[0] & (1 << ((n) % 32)))
- X# define FD_ZERO(p) memset ((char *)(p), '\0', sizeof(*(p)))
- X# endif
- X
- X# ifndef __NeXT__
- Xextern long int atoi (char *);
- X# else
- Xextern int atoi (const char *);
- X# endif
- Xextern long int write_to_fd (int, char *, long int);
- Xextern void report_progress (FILE *, char *, BOOLEAN);
- Xextern char *upcase (char *);
- Xextern char *_strstr (char *, char *);
- X
- Xextern FILE *report;
- X
- Xint ilp_server_response (int, int);
- Xint connect_to_ilp_server (char *, int);
- Xint sighandle (int);
- Xint urg_data (int);
- Xint alarm_clock (int);
- Xlong int read_from_fd (int, long int, int, int);
- Xint open_file (char *, int, int);
- Xint check_server_response (int, char *, int);
- Xint check_for_redirection (char *, char *);
- X
- Xlong int nbytes, sock_fd;
- Xint to_file, prompt_len, ofd, check_sio, append_output = 0, timed_out;
- Xchar args [256];
- Xvoid (*f1)(), (*f2)(), (*f3)();
- X# ifdef HAVE_SETJMP_H
- Xjmp_buf env;
- X# endif
- X
- X#else
- X# include "ilpp.h"
- X#endif
- X
- X#ifdef __STDC__
- X# include <stdarg.h>
- Xint silp (char *, int, char *, char *, int, char *, char *, ...);
- Xextern char *tsprintf (char *, ...);
- X#else
- X# include <varargs.h>
- Xint silp ();
- Xextern char *tsprintf ();
- X#endif
- X
- X/*
- X Main function. Connect to server, issue requests and receive replies.
- X
- X Returns: an ILPP code or -1 on error.
- X*/
- X
- X#ifdef __STDC__
- Xint silp (char *Host, int port, char *Login, char *Passwd,
- X int response_timeout, char *outfile, char *control, ...)
- X#else
- Xint silp (Host, port, Login, Passwd, response_timeout, outfile, control,
- X va_alist)
- Xchar *Host, *outfile, *Login, *Passwd, *control;
- Xint port, response_timeout;
- Xva_dcl
- X#endif
- X{
- X#ifndef GO_INTERACTIVE
- X return SYS_ERROR;
- X#else
- X char *buf, *tmp, infile [256], wbuf [256], *sep = "IUL:", *s, *r, rhost [256];
- X char login [256], passwd [256], host [256], raddr [256], taddr [256];
- X char version [80];
- X int cmd, i, sprompt_len, timeout, rfd, bytes_alloced = 0, naddr, naddr2,
- X _prompt_len, rtc = response_timeout;
- X struct stat stat_buf;
- X struct hostent *hp, *thp;
- X struct in_addr _addr;
- X va_list ap;
- X
- X
- X check_sio = 0;
- X strncpy (login, Login, 255);
- X strncpy (passwd, Passwd, 255);
- X strncpy (host, Host, 255);
- X login [255] = passwd [255] = host [255] = EOS;
- X if ((ofd = open (outfile, O_CREAT | O_WRONLY | O_APPEND, 0600)) < 0) {
- X report_progress (report, tsprintf ("\nsilp(): Cannot open %s", outfile),
- X TRUE);
- X return -1;
- X }
- X bytes_alloced = 256;
- X if ((buf = (char *) malloc (bytes_alloced * sizeof (char))) == NULL) {
- X report_progress (report, "\nsilp(): malloc() failed", TRUE);
- X close (ofd);
- X return -1;
- X }
- X
- X# ifdef HAVE_SETJMP_H
- X# ifdef SIGIO
- X f1 = (void (*)()) signal (SIGIO, (void (*)()) urg_data);
- X# endif
- X# ifdef SIGURG
- X f2 = (void (*)()) signal (SIGURG, (void (*)()) urg_data);
- X# endif
- X f3 = (void (*)()) signal (SIGPIPE, (void (*)()) sighandle);
- X# endif
- X# ifdef __STDC__
- X va_start (ap, control);
- X# else
- X va_start (ap);
- X# endif
- X
- X upcase (login);
- X s = login;
- X i = 0;
- X while (i < MAX_HOPS && (s = _strstr (s, sep)))
- X ++i,
- X ++s;
- X if (i >= MAX_HOPS) {
- X write_to_fd (ofd, "Too many hops.\n", 15);
- X cmd = PEER_UNAVAIL;
- X goto abort;
- X }
- X s = login;
- X upcase (host);
- X while ((s = _strstr (s, sep))) { /* Check for loop */
- X s += 4; /* Point to remote host */
- X sscanf (s, "%s", rhost);
- X if ((r = strchr (rhost, ';')))
- X *r = EOS;
- X thp = hp = gethostbyname (host);
- X if (hp) { /* Just got IP address(es) of host */
- X if ((thp = (struct hostent *) malloc (sizeof (struct hostent))) == NULL) {
- X report_progress (report, "\nsilp(): malloc() failed", TRUE);
- X close (ofd);
- X return -1;
- X }
- X memcpy ((char *) thp, (char *) hp, sizeof (*hp));
- X#ifdef h_addr
- X naddr = 0;
- X if ((thp->h_addr_list = (char **) malloc (sizeof (char *))) == NULL) {
- X report_progress (report, "\nsilp(): malloc() failed", TRUE);
- X close (ofd);
- X return -1;
- X }
- X while (hp->h_addr_list[naddr]) { /* Copy all IP addresses */
- X if ((thp->h_addr_list = (char **)
- X realloc (thp->h_addr_list, (naddr + 2) * sizeof (char *))) == NULL) {
- X report_progress (report, "\nsilp(): realloc() failed", TRUE);
- X close (ofd);
- X return -1;
- X }
- X if ((thp->h_addr_list[naddr] =
- X (char *) malloc (thp->h_length * sizeof (char))) == NULL) {
- X report_progress (report, "\nsilp(): malloc() failed", TRUE);
- X close (ofd);
- X return -1;
- X }
- X memcpy ((char *) thp->h_addr_list[naddr],
- X (char *) hp->h_addr_list[naddr], hp->h_length);
- X thp->h_addr_list[++naddr] = NULL;
- X }
- X naddr = 0;
- X while (thp->h_addr_list[naddr]) { /* For all target addresses */
- X memcpy ((char *) &_addr, (char *) thp->h_addr_list[naddr++],
- X thp->h_length);
- X strcpy (taddr, (char *) inet_ntoa (_addr));
- X hp = gethostbyname (rhost);
- X naddr2 = 0;
- X while (hp && hp->h_addr_list[naddr2]) { /* Check all hosts visited */
- X memcpy ((char *) &_addr, (char *) hp->h_addr_list[naddr2++],
- X hp->h_length);
- X strcpy (raddr, (char *) inet_ntoa (_addr));
- X if (!strcmp (taddr, raddr)) { /* Loop */
- X write_to_fd (ofd, "Loop detected.\n", 15);
- X cmd = PEER_UNAVAIL;
- X goto abort;
- X }
- X }
- X /* Assume gethostbyname() failed */
- X if (!strcmp (host, rhost) || !strcmp (taddr, rhost)) { /* Loop !!! */
- X write_to_fd (ofd, "Loop detected.\n", 15);
- X cmd = PEER_UNAVAIL;
- X goto abort;
- X }
- X }
- X naddr = 0;
- X while (thp->h_addr_list[naddr])
- X free ((char *) thp->h_addr_list[naddr++]);
- X free ((char **) thp->h_addr_list);
- X#else
- X if ((thp->h_addr = (char *) malloc ((strlen (hp->h_addr) + 1) *
- X sizeof (char))) == NULL) {
- X report_progress (report, "\nsilp(): malloc() failed", TRUE);
- X close (ofd);
- X return -1;
- X }
- X memcpy ((char *) thp->h_addr, (char *) hp->h_addr, hp->h_length);
- X memcpy ((char *) &_addr, (char *) thp->h_addr, thp->h_length);
- X strcpy (taddr, (char *) inet_ntoa (_addr));
- X hp = gethostbyname (rhost);
- X memcpy ((char *) &_addr, (char *) hp->h_addr, hp->h_length);
- X strcpy (raddr, (char *) inet_ntoa (_addr));
- X if (!strcmp (taddr, raddr)) { /* Loop */
- X write_to_fd (ofd, "Loop detected.\n", 15);
- X cmd = PEER_UNAVAIL;
- X goto abort;
- X }
- X free ((char *) thp->h_addr);
- X#endif
- X free ((struct hostent *) thp);
- X }
- X else { /* Host is an IP address */
- X naddr = 0;
- X hp = gethostbyname (rhost);
- X#ifdef h_addr
- X while (hp && hp->h_addr_list[naddr]) { /* Check all hosts visited */
- X memcpy ((char *) &_addr, (char *) hp->h_addr_list[naddr++],
- X hp->h_length);
- X strcpy (raddr, (char *) inet_ntoa (_addr));
- X if (!strcmp (raddr, host)) { /* Loop */
- X write_to_fd (ofd, "Loop detected.\n", 15);
- X cmd = PEER_UNAVAIL;
- X goto abort;
- X }
- X }
- X#else
- X memcpy ((char *) &_addr, (char *) hp->h_addr, hp->h_length);
- X strcpy (raddr, (char *) inet_ntoa (_addr));
- X if (!strcmp (raddr, host)) { /* Loop */
- X write_to_fd (ofd, "Loop detected.\n", 15);
- X cmd = PEER_UNAVAIL;
- X goto abort;
- X }
- X#endif
- X }
- X }
- X
- X if ((sock_fd = connect_to_ilp_server (host, port)) < 0)
- X if ((sock_fd = connect_to_ilp_server (host, (((port & 0xff00) >> 8) |
- X ((port & 0xff) << 8)))) < 0) {
- X write_to_fd (ofd, "Could not connect to host.\n", 27);
- X cmd = PEER_UNAVAIL;
- X goto abort;
- X }
- X
- X if ((cmd = ilp_server_response (sock_fd, response_timeout)) != CONNECT) {
- X write_to_fd (ofd, "Handshake failed, not an interactive ListProcessor \
- Xserver.\n", 59);
- X cmd = SYS_ERROR;
- X goto abort;
- X }
- X
- X# ifdef HAVE_SETJMP_H
- X if (!setjmp (env)) { /* No signal; proceed */
- X# endif
- X
- X if (check_server_response (cmd, args, response_timeout))
- X# ifdef HAVE_SETJMP_H
- X longjmp (env, 1);
- X# else
- X goto abort;
- X# endif
- X if ((timeout = nbytes) < response_timeout)
- X response_timeout = timeout;
- X sscanf (args, "%s %d %d\n", version, &_prompt_len, &sprompt_len);
- X
- X if ((cmd = ilp_server_response (sock_fd, response_timeout)) < 0)
- X# ifdef HAVE_SETJMP_H
- X longjmp (env, 1);
- X# else
- X goto abort;
- X# endif
- X check_server_response (cmd, args, response_timeout);
- X if (cmd == CONN_CLOSED || cmd == SERVER_BUSY || cmd == PEER_UNAVAIL ||
- X cmd == CONN_ABORTED || cmd == SYS_ERROR || cmd == CONN_TIMEOUT)
- X append_output = 1;
- X if (read_from_fd (sock_fd, nbytes, response_timeout, ofd) < 0)
- X# ifdef HAVE_SETJMP_H
- X longjmp (env, 1);
- X# else
- X goto abort;
- X# endif
- X if (cmd == CONN_CLOSED || cmd == SERVER_BUSY || cmd == PEER_UNAVAIL ||
- X cmd == CONN_ABORTED || cmd == SYS_ERROR || cmd == CONN_TIMEOUT)
- X# ifdef HAVE_SETJMP_H
- X longjmp (env, 1);
- X# else
- X goto abort;
- X# endif
- X prompt_len = _prompt_len;
- X strcat (login, "\n");
- X if (write_to_fd (sock_fd, login, strlen (login)) < 0)
- X# ifdef HAVE_SETJMP_H
- X longjmp (env, 1);
- X# else
- X goto abort;
- X# endif
- X if ((cmd = ilp_server_response (sock_fd, response_timeout)) < 0)
- X# ifdef HAVE_SETJMP_H
- X longjmp (env, 1);
- X# else
- X goto abort;
- X# endif
- X if (check_server_response (cmd, args, response_timeout))
- X# ifdef HAVE_SETJMP_H
- X longjmp (env, 1);
- X# else
- X goto abort;
- X# endif
- X if (cmd == PASSWORD_REQUIRED) {
- X strcat (passwd, "\n");
- X if (write_to_fd (sock_fd, passwd, strlen (passwd)) < 0)
- X# ifdef HAVE_SETJMP_H
- X longjmp (env, 1);
- X# else
- X goto abort;
- X# endif
- X }
- X else if (cmd == PEER_UNAVAIL)
- X# ifdef HAVE_SETJMP_H
- X longjmp (env, 1);
- X# else
- X goto abort;
- X# endif
- X
- X RESET (buf);
- X vsprintf (buf, control, ap);
- X va_end (ap);
- X strcat (buf, "\n__abort__\n"); /* Just in case */
- X while (cmd != CONN_CLOSED && cmd != CONN_ABORTED && cmd != CONN_TIMEOUT) {
- X check_sio = 0;
- X if ((cmd = ilp_server_response (sock_fd, response_timeout)) < 0) break;
- X if (check_server_response (cmd, args, response_timeout)) break;
- X if (cmd == TEST_FILE_PERMISSIONS) continue;
- X if (cmd != CONN_ABORTED && cmd != CONN_TIMEOUT)
- X if (read_from_fd (sock_fd, nbytes, response_timeout,
- X (cmd != MESSAGE ? ofd : 0)) < 0) break;
- X if (cmd == MESSAGE) {
- X response_timeout -= 10;
- X if (response_timeout <= 0)
- X response_timeout = 1;
- X continue;
- X }
- X check_sio = ! (append_output = 0);
- X if (cmd != CONN_CLOSED && cmd != CONN_ABORTED && cmd != CONN_TIMEOUT) {
- X response_timeout = rtc;
- X if (buf [0] == EOS) {
- X RESET (infile);
- X if ((rfd = check_for_redirection (buf, infile)) < 0)
- X strcpy (buf, "\n");
- X if (rfd >= 0 && infile [0] != EOS) { /* Input redirection */
- X fstat (rfd, &stat_buf);
- X if (!(stat_buf.st_mode & S_IFREG)) {
- X printf ("%s: Not a regular file\n", infile);
- X strcpy (buf, "\n");
- X goto skip;
- X }
- X if ((stat_buf.st_size + strlen (buf) + 2) > bytes_alloced) {
- X bytes_alloced = stat_buf.st_size + strlen (buf) + 2;
- X if ((buf = (char *) realloc (buf, bytes_alloced * sizeof (char))) ==
- X NULL) {
- X write_to_fd (ofd, "FATAL: internal memory error.\n", 30);
- X report_progress (report, "\nsilp(): realloc() failed", TRUE);
- X cmd = -1;
- X break;
- X }
- X }
- X i = strlen (buf);
- X if (read (rfd, &buf [strlen (buf)], stat_buf.st_size) <
- X stat_buf.st_size) {
- X write_to_fd (ofd, "FATAL: Failed to read all of the input \
- Xfile.\n", 45);
- X cmd = -1;
- X break;
- X }
- X buf [i + stat_buf.st_size] = EOS;
- X if (buf [i + stat_buf.st_size - 1] != '\n')
- X strcat (&buf [i + stat_buf.st_size], "\n");
- X close (rfd);
- X }
- X }
- X skip:
- X strncpy (wbuf, buf, 174);
- X while (!(tmp = strchr (wbuf, '\n')))
- X wbuf [174] = '\n';
- X if (tmp != wbuf) /* Not an empty line */
- X sprintf (tmp, " >> %s\n", outfile);
- X check_sio = 0;
- X if (write_to_fd (sock_fd, wbuf, strlen (wbuf)) < 0) break;
- X sprintf (buf, "%s", strchr (buf, '\n') + 1);
- X if (strncmp (wbuf, "quit", 4) && strncmp (wbuf, "exit", 4))
- X append_output = 1;
- X if (!strncmp (wbuf, "__abort__", 9))
- X break;
- X }
- X }
- X
- X# ifdef HAVE_SETJMP_H
- X } /* if (!setjmp (env)) ... */
- X else { /* Return from longjmp () */
- X }
- X# endif
- X
- X abort:
- X# ifdef HAVE_SETJMP_H
- X# ifdef SIGIO
- X signal (SIGIO, (void (*)()) f1);
- X# endif
- X# ifdef SIGURG
- X signal (SIGURG, (void (*)()) f2);
- X# endif
- X signal (SIGPIPE, (void (*)()) f3);
- X# endif
- X signal (SIGALRM, SIG_IGN);
- X if (sock_fd >= 0)
- X close (sock_fd);
- X close (ofd);
- X if (buf)
- X free ((char *) buf);
- X return cmd;
- X#endif
- X}
- X
- X#ifdef GO_INTERACTIVE
- X/*
- X Get server response. Store in 'nbytes' the number of bytes in the actual
- X message that follows, and in 'args' the (optional) file name.
- X
- X Returns: the server reply code, CONN_TIMEOUT, CONN_ABORTED, or -1 on
- X protocol errors.
- X*/
- X
- Xint ilp_server_response (int sock_fd, int response_timeout)
- X{
- X char buf [256];
- X int cmd = -1, i, bytes_to_read = 4, bytes_read = 0, value, nfds;
- X fd_set rfds;
- X struct timeval timeout;
- X
- X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
- X defined (apollo) || defined (unknown_port)
- X nfds = getdtablesize ();
- X# else
- X nfds = ulimit (UL_GDESLIM);
- X# endif
- X memset (buf, EOS, 256);
- X while (bytes_to_read) {
- X /* Get server command */
- X FD_ZERO (&rfds);
- X do {
- X FD_SET (sock_fd, &rfds);
- X timeout.tv_sec = timeout.tv_usec = response_timeout;
- X errno = 0;
- X value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
- X } while (value == -1 && errno == EINTR);
- X
- X if (value == 0) {
- X nbytes = 0;
- X write_to_fd (ofd, "Server response timeout.\n", 25);
- X return CONN_TIMEOUT;
- X }
- X else if (value < 0) {
- X write_to_fd (ofd, "select() failed\n", 16);
- X return -1;
- X }
- X
- X errno = 0;
- X /* Get server command */
- X bytes_read = read (sock_fd, &buf [4 - bytes_to_read], bytes_to_read);
- X if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
- X errno == ECONNREFUSED) {
- X nbytes = 0;
- X return CONN_ABORTED;
- X }
- X if (bytes_read > 0)
- X bytes_to_read -= bytes_read;
- X }
- X buf[3] = EOS;
- X cmd = atoi (buf);
- X i = 0;
- X do { /* Get # of bytes in actual message */
- X again1:
- X FD_ZERO (&rfds);
- X do {
- X FD_SET (sock_fd, &rfds);
- X timeout.tv_sec = timeout.tv_usec = response_timeout;
- X errno = 0;
- X value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
- X } while (value == -1 && errno == EINTR);
- X
- X if (value == 0) {
- X nbytes = 0;
- X write_to_fd (ofd, "Server response timeout.\n", 25);
- X return CONN_TIMEOUT;
- X }
- X else if (value < 0) {
- X write_to_fd (ofd, "select() failed\n", 16);
- X return -1;
- X }
- X
- X errno = 0;
- X if (read (sock_fd, &buf[i], 1) < 1) {
- X if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
- X errno == ECONNREFUSED) {
- X nbytes = 0;
- X return CONN_ABORTED;
- X }
- X if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
- X goto again1;
- X write_to_fd (ofd, "Protocol error in control string.\n", 34);
- X return -1;
- X }
- X i++;
- X } while (buf[i - 1] != ' ');
- X
- X buf[i - 1] = EOS;
- X nbytes = atoi (buf);
- X RESET (args);
- X i = 0;
- X do { /* Get filename (optional) */
- X again2:
- X FD_ZERO (&rfds);
- X do {
- X FD_SET (sock_fd, &rfds);
- X timeout.tv_sec = timeout.tv_usec = response_timeout;
- X errno = 0;
- X value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
- X } while (value == -1 && errno == EINTR);
- X
- X if (value == 0) {
- X nbytes = 0;
- X write_to_fd (ofd, "Server response timeout.\n", 25);
- X return CONN_TIMEOUT;
- X }
- X else if (value < 0) {
- X write_to_fd (ofd, "select() failed\n", 16);
- X return -1;
- X }
- X
- X errno = 0;
- X if (read (sock_fd, &args[i], 1) < 1) {
- X if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
- X errno == ECONNREFUSED)
- X return CONN_ABORTED;
- X if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
- X goto again2;
- X write_to_fd (ofd, "Protocol error in control string.\n", 34);
- X return -1;
- X }
- X ++i;
- X } while (args[i - 1] != '\n');
- X args[i - 1]= EOS;
- X return cmd;
- X}
- X
- X/*
- X Establish connection with unix-listproc. The socket is marked as
- X non-blocking.
- X
- X Returns: the socket file descriptor, or -1 on error.
- X*/
- X
- Xint connect_to_ilp_server (char *host, int port)
- X{
- X int sock_fd, sendbuf = BUFFSIZ, recvbuf = BUFFSIZ, value = 1, nfds, naddr = 0;
- X struct sockaddr_in sin;
- X struct hostent *hostentry;
- X struct timeval timeout;
- X fd_set readfds, writefds;
- X
- X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
- X defined (apollo) || defined (unknown_port)
- X nfds = getdtablesize ();
- X# else
- X nfds = ulimit (UL_GDESLIM);
- X# endif
- X timeout.tv_sec = timeout.tv_usec = 0;
- X if (!(hostentry = gethostbyname (host))) { /* Host name failed; try IP */
- X sin.sin_addr.s_addr = inet_addr (host);
- X if (! (hostentry = gethostbyaddr ((char *) &sin.sin_addr,
- X sizeof (struct in_addr),
- X AF_INET))) {
- X write_to_fd (ofd, "Invalid host.\n", 14);
- X return -1;
- X }
- X }
- X
- X do {
- X if ((sock_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
- X report_progress (report, "\nconnect_to_ilp_server(): Could not create \
- Xsocket", TRUE);
- X return -1;
- X }
- X if (setsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, (char *) &sendbuf,
- X sizeof (sendbuf)) < 0)
- X report_progress (report, "\nconnect_to_ilp_server(): WARNING: Could not \
- Xset send-buffer size: setsockopt() error", TRUE);
- X if (setsockopt (sock_fd, SOL_SOCKET, SO_RCVBUF, (char *) &recvbuf,
- X sizeof (recvbuf)) < 0)
- X report_progress (report, "\nconnect_to_ilp_server(): WARNING: Could not \
- Xset receive-buffer size: setsockopt() error", TRUE);
- X if (setsockopt (sock_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &value,
- X sizeof (value)) < 0)
- X report_progress (report, "\nconnect_to_ilp_server(): WARNING: Cannot \
- Xtoggle keep-alive connections: setsockopt() error", TRUE);
- X
- X#ifdef h_addr
- X memcpy ((char *) &sin.sin_addr.s_addr,
- X (char *) hostentry->h_addr_list[naddr++],
- X hostentry->h_length);
- X#else
- X memcpy ((char *) &sin.sin_addr.s_addr,
- X (char *) hostentry->h_addr,
- X hostentry->h_length);
- X#endif
- X sin.sin_family = AF_INET;
- X sin.sin_port = htons (port);
- X memset (sin.sin_zero, EOS, sizeof (sin.sin_zero));
- X if (connect (sock_fd, (struct sockaddr *) &sin,
- X sizeof (struct sockaddr_in)) < 0) {
- X if (errno != EINPROGRESS) {
- X#ifdef h_addr
- X if (!hostentry->h_addr_list[naddr]) {
- X#endif
- X close (sock_fd);
- X return -1;
- X#ifdef h_addr
- X }
- X else {
- X close (sock_fd);
- X continue;
- X }
- X#endif
- X }
- X FD_ZERO (&readfds);
- X FD_ZERO (&writefds);
- X do {
- X FD_SET (sock_fd, &readfds);
- X FD_SET (sock_fd, &writefds);
- X errno = 0;
- X value = select ((nfds > 0 ? nfds : 20), &readfds, &writefds, NULL,
- X &timeout);
- X } while (value == -1 && errno == EINTR);
- X
- X if (value < 0) {
- X close (sock_fd);
- X return -1;
- X }
- X break; /* Successful connection */
- X }
- X else
- X break;
- X } while (007);
- X# ifdef NONBLOCKING_IO
- X if (fcntl (sock_fd, F_SETFL, (fcntl (sock_fd, F_GETFL, 0) | O_NDELAY)) < 0) {
- X report_progress (report, "\nconnect_to_ilp_server(): Could not set \
- Xnon-blocking I/O", TRUE);
- X close (sock_fd);
- X return -1;
- X }
- X# endif
- X# ifdef HAVE_SETJMP_H
- X# if defined (sco) || defined (M_XENIX) || defined (M_UNIX)
- X if (ioctl (sock_fd, I_SETSIG, S_INPUT) < 0) {
- X report_progress (report, "\nconnect_to_ilp_server(): Cannot set SIGIO",
- X TRUE);
- X close (sock_fd);
- X return -1;
- X }
- X# else
- X# ifdef F_SETOWN
- X if (fcntl (sock_fd, F_SETOWN, getpid()) < 0) {
- X report_progress (report, "\nconnect_to_ilp_server(): Cannot assign \
- Xsocket to process group", TRUE);
- X close (sock_fd);
- X return -1;
- X }
- X# elif defined (SIOCSPGRP)
- X value = -getpid();
- X if (ioctl (sock_fd, SIOCSPGRP, (char *) &value) < 0) {
- X report_progress (report, "\nconnect_to_ilp_server(): Cannot assign \
- Xsocket to process group", TRUE);
- X close (sock_fd);
- X return -1;
- X }
- X# else
- X report_progress (report, "\nconnect_to_ilp_server(): Cannot assign \
- Xsocket to process group", TRUE);
- X close (sock_fd);
- X return -1;
- X# endif
- X# ifdef FASYNC
- X if (fcntl (sock_fd, F_SETFL, (fcntl (sock_fd, F_GETFL, 0) | FASYNC)) < 0) {
- X report_progress (report, "\nconnect_to_ilp_server(): Cannot set \
- Xasynchronous I/O for socket", TRUE);
- X close (sock_fd);
- X return -1;
- X }
- X# elif defined (FIOASYNC)
- X value = 1;
- X if (ioctl (sock_fd, FIOASYNC, (char *) &value) < 0) {
- X report_progress (report, "\nconnect_to_ilp_server(): Cannot set \
- Xasynchronous I/O for socket", TRUE);
- X close (sock_fd);
- X return -1;
- X }
- X# else
- X report_progress (report, "\nconnect_to_ilp_server(): Cannot set \
- Xasynchronous I/O for socket", TRUE);
- X close (sock_fd);
- X return -1;
- X# endif
- X# endif
- X# endif
- X return sock_fd;
- X}
- X
- X# ifdef HAVE_SETJMP_H
- X/*
- X Handle signals; the client sends an '__abort__' command and returns (long
- X jump); '__abort__' causes the other end to shut down.
- X*/
- X
- Xint sighandle (int sig)
- X{
- X check_sio = 0;
- X write (sock_fd, "__abort__\n", 10);
- X longjmp (env, 1);
- X}
- X
- X/*
- X Urgent data from server; read it and return. Urgent data is received
- X when a connection is timed out or when the server shuts down.
- X*/
- X
- Xint urg_data (int sig)
- X{
- X int cmd;
- X
- X if (!check_sio) {
- X signal (sig, (void (*)()) urg_data);
- X return 0;
- X }
- X signal (sig, SIG_IGN);
- X if ((cmd = ilp_server_response (sock_fd, 30)) >= 0)
- X if (cmd == CONN_ABORTED || cmd == CONN_TIMEOUT || cmd == CONN_CLOSED)
- X check_server_response (cmd, args, 30),
- X append_output = 1,
- X read_from_fd (sock_fd, nbytes, 30, ofd);
- X longjmp (env, 1);
- X}
- X# endif
- X
- X/*
- X Alarm signals a server timeout.
- X*/
- X
- Xint alarm_clock (int sig)
- X{
- X timed_out = 1;
- X signal (sig, (void (*)()) alarm_clock);
- X}
- X
- X/*
- X Read from a socket and write to ofd.
- X
- X Returns: the actual number of bytes read on succes, or the negative of
- X that number (or -1) on error.
- X*/
- X
- Xlong int read_from_fd (int rfd, long int bytes_to_read, int response_timeout,
- X int ofd)
- X{
- X long int bytes_read, total_bytes = 0;
- X char buf [BUFFSIZ];
- X
- X timed_out = 0;
- X signal (SIGALRM, (void (*)()) alarm_clock);
- X alarm (response_timeout);
- X if (bytes_to_read <= 0)
- X return 0;
- X errno = 0;
- X while ((bytes_read = read (rfd, buf, MIN (bytes_to_read, BUFFSIZ))) <
- X bytes_to_read) {
- X if (bytes_read < 0 && errno && errno != EWOULDBLOCK && errno != EAGAIN &&
- X errno != EINTR
- X#ifdef ERESTART
- X && errno != ERESTART
- X#endif
- X ) {
- X char error [256];
- X sprintf (error, "\nread_from_fd(): ");
- X switch (errno) {
- X case EBADF: strcat (error, "Bad file number"); break;
- X case EFAULT: strcat (error, "Bad address"); break;
- X case EFBIG: strcat (error, "File limit reached"); break;
- X case EINVAL: strcat (error, "Negative seek pointer"); break;
- X case EIO: strcat (error, "I/O error"); break;
- X case ENOSPC: strcat (error, "No space left on device"); break;
- X case ENXIO: strcat (error, "No such device or address"); break;
- X case ERANGE: sprintf (error + strlen (error), "Bytes to read (%ld) \
- Xout of range", bytes_to_read); break;
- X#ifdef ENETRESET
- X case ENETRESET: strcat (error, "Network dropped connection"); break;
- X#endif
- X default: sprintf (error + strlen (error), "Error number %d", errno);
- X }
- X report_progress (report, error, TRUE);
- X return (total_bytes > 0 ? -total_bytes : -1);
- X }
- X else if (timed_out)
- X return (total_bytes > 0 ? -total_bytes : -1);
- X if (bytes_read > 0) {
- X total_bytes += bytes_read;
- X bytes_to_read -= bytes_read;
- X if (to_file) {
- X if (bytes_to_read < prompt_len)
- X to_file = 0;
- X if (ofd && write_to_fd (ofd, buf,
- X (bytes_to_read < prompt_len ?
- X bytes_read - prompt_len + bytes_to_read :
- X bytes_read)) < 0)
- X return (total_bytes > 0 ? -total_bytes : -1);
- X }
- X else if (append_output)
- X if (ofd, write_to_fd (ofd, buf,
- X (bytes_to_read < prompt_len ?
- X bytes_read - prompt_len + bytes_to_read :
- X bytes_read)) < 0)
- X return (total_bytes > 0 ? -total_bytes : -1);
- X }
- X errno = 0;
- X }
- X if (bytes_read > 0) {
- X total_bytes += bytes_read;
- X if ((append_output || to_file) && bytes_read > prompt_len)
- X if (ofd && write_to_fd (ofd, buf, bytes_read - prompt_len) < 0)
- X return -1;
- X }
- X to_file = 0;
- X signal (SIGALRM, SIG_IGN);
- X return total_bytes;
- X}
- X
- X/*
- X Open a file for writing or appending. If 'test' is set, make sure
- X the file is writeable, notify the server and close the file; else prepare
- X for the transfer. When the server is inquiring about a file's write
- X permissions it sends zero bytes as the length of the message.
- X
- X Returns: 0 on succes, -1 otherwise.
- X*/
- X
- Xint open_file (char *file, int mode, int test)
- X{
- X char msg [MAX_LINE];
- X int fd;
- X
- X if ((fd = open (file, O_CREAT | mode, 0600)) < 0)
- X to_file = 0,
- X sprintf (msg, "%s: Permission denied.\n", file),
- X write_to_fd (ofd, msg, strlen (msg)),
- X nbytes = prompt_len,
- X sprintf (msg, "%d", PERMISSION_DENIED);
- X else {
- X if (nbytes > 0)
- X to_file = 1;
- X else
- X sprintf (msg, "%d", OK);
- X close (fd);
- X }
- X if (test)
- X if (write_to_fd (sock_fd, msg, strlen (msg)) < 0)
- X return -1;
- X return 0;
- X}
- X
- X/*
- X Identify the server's response and take appropriate action.
- X
- X Returns: 0 on success, -1 otherwise.
- X*/
- X
- Xint check_server_response (int cmd, char *file, int response_timeout)
- X{
- X switch (cmd) {
- X case OK:
- X case CONNECT:
- X case SYNTAX_ERROR:
- X case INVALID_REQ:
- X case BAD_ARCHIVE:
- X case RESTRICTED_REQ:
- X case NOT_OWNER:
- X case SYS_ERROR:
- X case SERVER_BUSY:
- X case PERMISSION_DENIED:
- X case CONN_CLOSED:
- X case PEER_UNAVAIL:
- X case MORE_INPUT_REQUIRED:
- X case MESSAGE:
- X case CONTINUED: break;
- X case PASSWORD_REQUIRED:
- X if (read_from_fd (sock_fd, nbytes, response_timeout, ofd) < 0)
- X return -1;
- X break;
- X case CONN_ABORTED:
- X case CONN_TIMEOUT: return -1; break;
- X case TEST_FILE_PERMISSIONS:
- X if (open_file (file, O_WRONLY | O_APPEND, 1)) return -1;
- X break;
- X case WRITE_TO_FILE_ASC:
- X if (open_file (file, O_WRONLY | O_TRUNC, 0)) return -1;
- X break;
- X case WRITE_TO_FILE_BIN:
- X if (open_file (file, O_WRONLY | O_TRUNC, 0)) return -1;
- X break;
- X case APPEND_TO_FILE_ASC:
- X if (open_file (file, O_WRONLY | O_APPEND, 0)) return -1;
- X break;
- X case APPEND_TO_FILE_BIN:
- X if (open_file (file, O_WRONLY | O_APPEND, 0)) return -1;
- X break;
- X default: write_to_fd (ofd, "Protocol error.\n", 16); return -1;
- X }
- X return 0;
- X}
- X
- X/*
- X Check for input redirection, and if so check for for permissions too.
- X
- X Returns: the opened file descriptor on succes, -1 on error.
- X*/
- X
- Xint check_for_redirection (char *buf, char *infile)
- X{
- X char *redirect, *s;
- X int fd = 0;
- X
- X if ((redirect = strrchr (buf, '<')) != NULL)
- X if (redirect != buf && *(redirect - 1) == '\\')
- X sprintf (redirect - 1, "%s", redirect); /* Remove \ */
- X else {
- X RESET (infile);
- X sscanf (redirect + 1, "%s", infile);
- X if (infile [0] == EOS) {
- X write_to_fd (ofd, "Invalid null input redirect.\n", 29);
- X return -1;
- X }
- X if ((fd = open (infile, O_RDONLY)) < 0) {
- X write_to_fd (ofd, "File not found or inadequate permissions.\n", 42);
- X return -1;
- X }
- X s = redirect + 1; /* Remove < and file name */
- X while (*s == ' ' || *s == '\t') ++s;
- X while (*s != ' ' && *s != '\t' && *s != '\n') ++s;
- X sprintf (redirect, "%s", s);
- X }
- X return fd;
- X}
- X#endif
- *-*-END-of-src/silp.c-*-*
- echo x - src/start.c
- sed 's/^X//' >src/start.c <<'*-*-END-of-src/start.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | LISTPROCESSOR SYSTEM HOUSEKEEPER |
- X | |
- X | Version 2.8 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X This is the proper way of starting the system. The program verifies
- X that no other serverd, queued, list or listproc programs are running on the
- X system (and kills them before proceeding -- after confirming),
- X makes sure the required files exist (and creates new ones if missing --
- X after confirming), backs up all reports into files with extension .acc,
- X creates new directories for new mailing lists as necessary,
- X and finally spawns serverd. start reports to REPORT_START.
- X
- X COMMAND LINE OPTIONS:
- X -k: just kill all pertinent programs that may already be running; no
- X mailing list is started in this case.
- X -c: Do not confirm before killing a process.
- X -r: Do not report; useful when starting up when system is rebooted.
- X -s: After a process is killed, start sleeps for some time. This turns
- X sleeping off -- to be used only when restarting the system via
- X a 'restart' request.
- X
- X WARNING: The program won't work correctly in the absence of an extended
- X egrep facility that does matching at the end of a line with a $ and
- X accepts multiple regular expressions separated by a |. In this case,
- X the user may have to manually look for and terminate any such programs.
- X Also when the output of the 'ps' command exceeds 80 characters (due perhaps
- X to long path names) the user may again have to terminate programs by hand.
- X Note that a file locking mechanism for serverd, list and listproc is used
- X to ensure against multiple executions of the same program.
- X
- X WARNING: When using the SYSV ps command and it chops output to 80 characters,
- X start may not be able to locate processes already running; this may occur if
- X the path to HOMEDIR is too long.
- X*/
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <string.h>
- X#ifdef SYSLOG
- X# ifdef ultrix
- X# include <sys/syslog.h>
- X# else
- X# include <syslog.h>
- X# endif
- X#endif
- X#include <signal.h>
- X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
- X && !defined (sequent) && !defined (unknown_port)
- X# include <malloc.h>
- X#endif
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <sys/stat.h>
- X#include "defs.h"
- X#include "start.h"
- X#include "struct.h"
- X#include "global.h"
- X#if defined (__NeXT__) || defined (unknown_port)
- X# include "next.h"
- X#endif
- X
- X/*
- X Function prototypes:
- X*/
- X
- X#ifdef __STDC__
- X# include "ansi/misc.h"
- X# include <stdarg.h>
- Xextern int syscom (char *, ...);
- Xextern char *tsprintf (char *, ...);
- X#else
- X# include "nonansi/misc.h"
- X# include <varargs.h>
- Xextern int syscom ();
- Xextern char *tsprintf ();
- X#endif
- Xextern int sys_config (FILE *, SYS *);
- Xextern char *extract_filename (char *);
- Xextern void report_progress (FILE *, char *, int);
- Xextern int _getopt (int, char **, char *);
- Xextern void setup_string (char *, char *, char *);
- Xextern void shrink (char *);
- Xextern char *mystrdup (char *);
- Xextern int echo (char *, char *);
- Xextern int echo_append (char *, char *);
- Xextern int mv (char *, char *);
- Xextern int cp (char *, char *);
- Xextern int cat (char *, char *);
- Xextern int cat_append (char *, char *);
- Xextern int touch (char *);
- Xextern void init_signals (void);
- Xextern void catch_signals (void);
- Xextern int otoi (char *);
- X
- Xvoid main (int, char **);
- XBOOLEAN check_for (char *, FILE *, BOOLEAN, BOOLEAN);
- Xvoid check_unprocessed (char *, FILE *, BOOLEAN);
- Xvoid usage (void);
- Xvoid backup (char *, char *);
- Xvoid start_config (char *);
- Xint gexit (int);
- Xchar get_response (void);
- X
- Xvoid main (int argc, char **argv)
- X{
- X char command [256];
- X char line [MAX_LINE];
- X char dir [MAX_LINE];
- X char *addr1, *addr2, *addr3, *addr4, *options = "ckrs";
- X int c;
- X FILE *f, *p;
- X int i, nlists, pid, procs_killed = 0, procs;
- X BOOLEAN just_kill = FALSE, confirm = TRUE, do_report = TRUE, sleepok = TRUE;
- X char *tmpps, *tmpfound, *tmpnprocs;
- X struct stat stat_buf;
- X extern char *getenv();
- X
- X while ((c = _getopt (argc, argv, options)) != EOF)
- X switch ((char) c) {
- X case 'c': confirm = FALSE; break;
- X case 'k': just_kill = TRUE; break;
- X case 'r': do_report = FALSE; break;
- X case 's': sleepok = FALSE; tty_echo = FALSE; break;
- X case '?':
- X default:
- X usage();
- X }
- X
- X /* First make sure no other SERVERD programs are running. If so, kill
- X them all (after confirming) before proceeding. */
- X
- X init_signals ();
- X catch_signals ();
- X signal (SIGINT, (void (*)()) gexit);
- X signal (SIGALRM, SIG_IGN);
- X if ((mask = getenv ("ULISTPROC_UMASK")))
- X umask (otoi (mask));
- X else
- X mask = "066",
- X umask (S_IRWXG|S_IRWXO); /* 600 */
- X#ifdef SYSLOG
- X openlog ("ListProcessor: start", LOG_NDELAY
- X# ifndef i386
- X |LOG_NOWAIT
- X# endif
- X , SYSLOG);
- X# ifndef ultrix
- X setlogmask (LOG_UPTO (LOG_INFO));
- X# endif
- X#else
- X backup (REPORT_START, REPORT_START_ACC);
- X if ((report = fopen (REPORT_START, "a")) == NULL)
- X fprintf (stderr, "start: Could not open %s\n", REPORT_START),
- X START_ABORT;
- X chmod (REPORT_START, 384); /* 600 */
- X#endif
- X nlists = sys_config (report, &sys);
- X if (just_kill)
- X report_progress (report, "\n--- SHUTTING LISTPROCESSOR SYSTEM DOWN ---\n",
- X FALSE);
- X else
- X report_progress (report, "\n--- STARTING LISTPROCESSOR SYSTEM ---\n",
- X FALSE);
- X#ifndef _MINIX
- X if (sys.options & BSD_PS)
- X syscom ("ps -gx > %s", (tmpps = mystrdup (tmpnam (NULL))));
- X else
- X# ifdef __hp9000s800
- X syscom ("ps -ef | grep %s | sort > %s",
- X# else
- X syscom ("ps -ef | grep %s > %s",
- X# endif
- X ((addr1 = (char *) getenv ("LOGNAME")) == NULL ?
- X ((addr1 = (char *) getenv ("USER")) == NULL ? "server" : addr1) :
- X addr1), (tmpps = mystrdup (tmpnam (NULL))));
- X tty_echo = FALSE;
- X addr1 = extract_filename (LIST);
- X addr2 = extract_filename (SERVERD);
- X addr3 = extract_filename (SERVER);
- X addr4 = extract_filename (PQUEUE);
- X syscom ("egrep '%s |%s$|%s$|%s|%s$|%s |%s|%s |queued' %s > %s",
- X addr1, addr1, addr2, addr2, addr3, addr3, addr4, addr4, tmpps,
- X (tmpfound = mystrdup (tmpnam (NULL))));
- X free ((char *) addr1);
- X free ((char *) addr2);
- X free ((char *) addr3);
- X free ((char *) addr4);
- X unlink (tmpps);
- X free ((char *) tmpps);
- X if (sleepok)
- X tty_echo = TRUE;
- X if ((f = fopen (tmpfound, "r")) == NULL)
- X report_progress (report,
- X tsprintf ("Error opening %s. Aborting. %s", tmpfound,
- X ((just_kill == FALSE) ?
- X "System not started." : "")), TRUE),
- X START_ABORT;
- X
- X syscom ("wc -l %s > %s", tmpfound, (tmpnprocs = mystrdup (tmpnam (NULL))));
- X if ((p = fopen (tmpnprocs, "r")) != NULL) {
- X fscanf (p, "%d", &procs);
- X if (do_report)
- X report_progress (report,
- X tsprintf ("OLD LISTPROCESSOR PROCESSES RUNNING: %d\n",
- X procs), FALSE);
- X fclose (p);
- X unlink (tmpnprocs);
- X free ((char *) tmpnprocs);
- X }
- X else
- X report_progress (report,
- X tsprintf ("Error opening %s. Aborting. %s", tmpnprocs,
- X ((just_kill == FALSE) ?
- X "System not started." : "")), TRUE),
- X START_ABORT;
- X
- X while (!feof (f)) { /* get pid's and kill processes after confirming */
- X RESET (line);
- X fgets (line, MAX_LINE - 2, f);
- X if (line[0] != EOS) {
- X if (sys.options & BSD_PS)
- X sscanf (line, "%d ", &pid);
- X else
- X#ifdef __hp9000s800
- X sscanf (line, "%*s %s %d ", command, &pid);
- X#else
- X sscanf (line, "%s %d ", command, &pid);
- X#endif
- X if (confirm) {
- X# ifdef SIGSTOP
- X kill (pid, SIGSTOP);
- X# elif defined (SIGSTP)
- X kill (pid, SIGSTP);
- X# endif
- X c = EOS;
- X while (c != EOF && c != 'Y' && c != 'N' &&c != 'I') {
- X# ifdef SYSLOG
- X printf ("\n%s\n%c[7m%s%c[mKill it to proceed ? (capital Y/N/Ignore) ",
- X ((just_kill == FALSE) ?
- X "ERROR: another ListProcessor system program running:" :
- X "ListProcessor system program found:"),
- X 27, line, 27);
- X# else
- X report_progress (report,
- X tsprintf ("\n%s\n%c[7m%s%c[mKill it to \
- Xproceed ? (capital Y/N/Ignore) ",
- X ((just_kill == FALSE) ?
- X "ERROR: another ListProcessor system program running:" :
- X "ListProcessor system program found:"),
- X 27, line, 27), FALSE);
- X# endif
- X c = get_response ();
- X }
- X# ifdef SIGCONT
- X kill (pid, SIGCONT);
- X# elif defined (SIGCNT)
- X kill (pid, SIGCNT);
- X# endif
- X if (c == 'N' || c == EOF)
- X report_progress (report, tsprintf ("start aborted. %s\n",
- X ((just_kill == FALSE) ?
- X "System not started.":"")), TRUE),
- X unlink (tmpfound),
- X exit (1);
- X }
- X if (c == 'Y' || !confirm)
- X kill (pid, SIGINT),
- X ++procs_killed;
- X }
- X }
- X fclose (f);
- X unlink (tmpfound);
- X free ((char *) tmpfound);
- X if (sleepok)
- X sleep (2);
- X for (i = 0; pids[i]; i++)
- X if ((f = fopen (pids[i], "r")) != NULL) {
- X fscanf (f, "%d", &pid);
- X if (pid)
- X kill (pid, SIGINT),
- X ++procs_killed;
- X fclose (f);
- X unlink (pids[i]);
- X }
- X syscom (tsprintf ("if [ -f %s ]; then rm %s; fi", SERVER_PIDS, SERVER_PIDS));
- X syscom (tsprintf ("if [ -f %s ]; then rm %s; fi", TMP_LIVE_FILES,
- X TMP_LIVE_FILES));
- X syscom (tsprintf ("if [ -f %s ]; then rm %s; fi", REPLY_FILES, REPLY_FILES));
- X if (do_report)
- X report_progress (report, tsprintf ("OLD LISTPROCESSOR PROCESSES KILLED: \
- X%d\n", procs_killed), FALSE);
- X
- X if (just_kill) /* Done */
- X report_progress (report, "", -TRUE),
- X# ifdef SYSLOG
- X closelog (),
- X# else
- X fclose (report),
- X# endif
- X exit (0);
- X if (sleepok)
- X sleep (2);
- X#endif
- X
- X echo ("Serverd lock file", SERVERD_LOCK_FILE);
- X echo ("Pqueue lock file", PQUEUE_LOCK_FILE);
- X
- X backup (REPORT_SERVER, REPORT_SERVER_ACC);
- X backup (REPORT_SERVERD, REPORT_SERVERD_ACC);
- X backup (REPORT_PQUEUE, REPORT_PQUEUE_ACC);
- X SETUP_IGNOREDF;
- X check_for (server_ignoredf, report, do_report, confirm);
- X check_for (OWNERSF, report, do_report, confirm);
- X check_for (ALIASESF, report, do_report, confirm);
- X shrink (REPORT_CATMAIL);
- X syscom ("chmod u+s %s", CATMAIL);
- X for (i = 0; i < nlists; ++i) {
- X start_config (sys.lists[i].alias);
- X SETUP_DIR;
- X if (stat (dir, &stat_buf)) {
- X if (mkdir (dir, /*448*/ 0777 & (0777 ^ otoi (mask))))
- X report_progress (report, tsprintf ("Could not create directory %s", dir),
- X TRUE),
- X START_ABORT;
- X if (do_report)
- X report_progress (report, tsprintf ("*** New list %s ***\n",
- X sys.lists[i].alias), FALSE);
- X cp (server_ignoredf, dir);
- X syscom ("echo '^%s$' >> %s/%s", sys.lists[i].alias, dir, IGNORED);
- X echo_append (sys.lists[i].address, tsprintf ("%s/%s", dir, IGNORED));
- X syscom ("echo %s | sed 's/listproc/server/' | sed 's/listproc/server/' \
- X>> %s/%s", sys.server.address, dir, IGNORED);
- X touch (infof);
- X touch (welcomef);
- X touch (list_mail_f);
- X chmod (list_mail_f, /*416*/ 0666 & (0666 ^ otoi (mask)));
- X touch (tsprintf ("%s/%s", dir, MODERATED_MAIL_FILE));
- X chmod (tsprintf ("%s/%s", dir, MODERATED_MAIL_FILE),
- X 0666 & (0666 ^ otoi (mask)));
- X }
- X check_for (subscribersf, report, do_report, confirm);
- X if (!check_for (aliasesf, report, do_report, confirm))
- X echo_append (DEFAULT_ALIASES, aliasesf);
- X check_for (newsf, report, do_report, confirm);
- X check_for (peersf, report, do_report, confirm);
- X check_for (restrictedf, report, do_report, confirm);
- X check_unprocessed (sys.lists[i].alias, report, do_report);
- X backup (report_listf, report_list_accf);
- X }
- X syscom ("%s %s &", SERVERD, sys.serverd_cmdoptions);
- X report_progress (report, "", -TRUE);
- X#ifdef SYSLOG
- X closelog ();
- X#else
- X fclose (report);
- X#endif
- X exit (0);
- X}
- X
- X/*
- X Make sure that file 's' exists. Create a new one if necessary. Return
- X TRUE if file exists, FALSE otherwise.
- X*/
- X
- XBOOLEAN check_for (char *s, FILE *report, BOOLEAN do_report, BOOLEAN confirm)
- X{
- X int c = EOS;
- X struct stat stat_buf;
- X
- X if (stat (s, &stat_buf)) { /* make sure we have file 's' */
- X if (confirm) {
- X while (c != EOF && c != 'Y' && c != 'N') {
- X if (do_report)
- X#ifdef SYSLOG
- X printf ("No %s file found. Create a new one? (capital Y/N) ",s),
- X#else
- X report_progress (report, tsprintf ("No %s file found. Create a new \
- Xone? (capital Y/N) ",s), FALSE);
- X#endif
- X c = get_response ();
- X }
- X if (c == 'N' || c == EOF)
- X START_ABORT;
- X }
- X touch (s);
- X return FALSE;
- X }
- X return TRUE;
- X}
- X
- X/*
- X Check for incomplete delivery for a list during the last run. The files
- X .unprocessed.* in the list's directory signify undelivered mail for
- X a subset of the subscribers/newsgroups/peers. Prepend the last undelivered
- X messages to the mail file, so that they are distributed again to the remaining
- X subscribers/newsgroups/peers.
- X*/
- X
- Xvoid check_unprocessed (char *list, FILE *report, BOOLEAN do_report)
- X{
- X struct stat stat_buf;
- X char *tmpmail;
- X
- X if (!stat (unprocessed_subscribersf, &stat_buf) ||
- X !stat (unprocessed_peersf, &stat_buf) ||
- X !stat (unprocessed_newsf, &stat_buf) ||
- X !stat (unprocessed_digestf, &stat_buf) ||
- X !stat (unprocessed_messages, &stat_buf)) { /* Last delivery incomplete */
- X if (do_report)
- X report_progress (report, tsprintf ("\nList %s did not complete last \
- Xdelivery\n", list), FALSE);
- X if (stat (unprocessed_messages, &stat_buf) &&
- X stat (unprocessed_digestf, &stat_buf)) {
- X if (do_report)
- X report_progress (report, tsprintf ("Last set of mail messages for \
- Xlist %s lost; cannot resume delivery\n", list), FALSE);
- X unlink (unprocessed_subscribersf);
- X unlink (unprocessed_peersf);
- X unlink (unprocessed_newsf);
- X return;
- X }
- X else if (do_report)
- X report_progress (report, "Mail will be delivered to the remaining \
- Xsubscribers/newsgroups/peers shortly\n", FALSE);
- X /* Create empty .unprocessed files for subscribers/newsgroups/peers
- X that do not exist. */
- X touch (unprocessed_subscribersf);
- X touch (unprocessed_peersf);
- X touch (unprocessed_newsf);
- X /* Now prepend undelivered message(s) to the mail file */
- X mv (list_mail_f, (tmpmail = mystrdup (tmpnam (NULL))));
- X cat (unprocessed_messages, list_mail_f);
- X cat_append (tmpmail, list_mail_f);
- X unlink (tmpmail);
- X free ((char *) tmpmail);
- X unlink (unprocessed_messages);
- X chmod (list_mail_f, /*416*/ 0666 & (0666 ^ otoi (mask)));
- X }
- X}
- X
- X/*
- X Append 'src' to 'dest' and create a brand new 'src'.
- X*/
- X
- Xvoid backup (char *src, char *dest)
- X{
- X struct stat stat_buf;
- X
- X if (!stat (src, &stat_buf)) /* prepare for backup */
- X cat_append (src, dest),
- X chmod (dest, 384), /* 600 */
- X unlink (src),
- X touch (src),
- X chmod (src, 384);
- X}
- X
- X/*
- X Print usage.
- X*/
- X
- Xvoid usage ()
- X{
- X fprintf (stderr, "Usage: start [-k] [-c] [-r]\n\
- X-k: Just kill any ListProcessor system programs running.\n\
- X-c: Do not confirm before killing processes.\n\
- X-r: Restrict reporting to screen.\n");
- X exit (1);
- X}
- X
- Xvoid start_config (char *alias)
- X{
- X setup_string (subscribersf, alias, SUBSCRIBERS);
- X setup_string (aliasesf, alias, ALIASES);
- X setup_string (newsf, alias, NEWSF);
- X setup_string (peersf, alias, PEERS);
- X setup_string (restrictedf, alias, RESTRICTED);
- X setup_string (ignoredf, alias, IGNORED);
- X setup_string (report_listf, alias, REPORT_LIST);
- X setup_string (infof, alias, INFO_FILE);
- X setup_string (welcomef, alias, WELCOME_FILE);
- X setup_string (unprocessed_subscribersf, alias, UNPROC_SUBSCRIBERS);
- X setup_string (unprocessed_peersf, alias, UNPROC_PEERS);
- X setup_string (unprocessed_newsf, alias, UNPROC_NEWS);
- X setup_string (unprocessed_messages, alias, UNPROC_MESSAGES);
- X setup_string (unprocessed_digestf, alias, UNPROC_DIGEST);
- X setup_string (list_mail_f, alias, LIST_MAIL_FILE);
- X setup_string (report_list_accf, alias, REPORT_LIST_ACC);
- X}
- X
- X/*
- X Required to avoid undefined symbols.
- X*/
- X
- Xint gexit (int exitcode)
- X{
- X exit (exitcode);
- X}
- X
- X/*
- X Get a one-character response from stdin.
- X*/
- X
- Xchar get_response ()
- X{
- X char c;
- X
- X fflush (stdout);
- X fflush (stdin);
- X c = fgetc (stdin);
- X
- X if (c != '\n' && c != EOF)
- X while (fgetc (stdin) != '\n');
- X fflush (stdin);
- X return c;
- X}
- *-*-END-of-src/start.c-*-*
- echo x - src/strftime.c
- sed 's/^X//' >src/strftime.c <<'*-*-END-of-src/strftime.c-*-*'
- X#ifndef lint
- X#ifndef NOID
- Xstatic char elsieid[] = "@(#)strftime.c 7.1";
- X/*
- X** Based on the UCB version whose ID appears below.
- X** This is ANSIish only when time is treated identically in all locales and
- X** when "multibyte character == plain character".
- X*/
- X#endif /* !defined NOID */
- X#endif /* !defined lint */
- X/*
- X * Copyright (c) 1989 The Regents of the University of California.
- X * All rights reserved.
- X *
- X * Redistribution and use in source and binary forms are permitted
- X * provided that the above copyright notice and this paragraph are
- X * duplicated in all such forms and that any documentation,
- X * advertising materials, and other materials related to such
- X * distribution and use acknowledge that the software was developed
- X * by the University of California, Berkeley. The name of the
- X * University may not be used to endorse or promote products derived
- X * from this software without specific prior written permission.
- X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- X */
- X
- X#if defined(LIBC_SCCS) && !defined(lint)
- Xstatic char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89";
- X#endif /* LIBC_SCCS and not lint */
- X
- X#include <sys/types.h>
- X#include <time.h>
- X#ifdef HAVE_TZFILE_H
- X# include <tzfile.h>
- X#else
- X# define TM_YEAR_BASE 1900
- X#endif
- X
- Xstatic char *afmt[] = {
- X "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
- X};
- Xstatic char *Afmt[] = {
- X "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
- X "Saturday",
- X};
- Xstatic char *bfmt[] = {
- X "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
- X "Oct", "Nov", "Dec",
- X};
- Xstatic char *Bfmt[] = {
- X "January", "February", "March", "April", "May", "June", "July",
- X "August", "September", "October", "November", "December",
- X};
- X
- Xstatic size_t gsize;
- Xstatic char *pt;
- X
- Xstatic void _add();
- Xstatic void _conv();
- Xstatic void _fmt();
- X
- Xsize_t
- Xucb_strftime(s, maxsize, format, t)
- X char *s;
- X char *format;
- X size_t maxsize;
- X struct tm *t;
- X{
- X pt = s;
- X gsize = maxsize;
- X _fmt(format, t);
- X if (gsize <= 0)
- X return(0);
- X *pt = '\0';
- X return(maxsize - gsize);
- X}
- X
- Xstatic void
- X_fmt(format, t)
- X register char *format;
- X struct tm *t;
- X{
- X for (; *format; ++format) {
- X if (*format == '%')
- X switch(*++format) {
- X case '\0':
- X --format;
- X break;
- X case 'A':
- X if (t->tm_wday < 0 || t->tm_wday > 6)
- X _add("?");
- X else _add(Afmt[t->tm_wday]);
- X continue;
- X case 'a':
- X if (t->tm_wday < 0 || t->tm_wday > 6)
- X _add("?");
- X else _add(afmt[t->tm_wday]);
- X continue;
- X case 'B':
- X if (t->tm_mon < 0 || t->tm_mon > 11)
- X _add("?");
- X else _add(Bfmt[t->tm_mon]);
- X continue;
- X case 'b':
- X case 'h':
- X if (t->tm_mon < 0 || t->tm_mon > 11)
- X _add("?");
- X else _add(bfmt[t->tm_mon]);
- X continue;
- X case 'c':
- X _fmt("%D %X", t);
- X continue;
- X case 'C':
- X _fmt("%a %b %e %X %Y", t);
- X continue;
- X case 'D':
- X case 'x':
- X _fmt("%m/%d/%y", t);
- X continue;
- X case 'd':
- X _conv(t->tm_mday, 2, '0');
- X continue;
- X case 'e':
- X _conv(t->tm_mday, 2, ' ');
- X continue;
- X case 'H':
- X _conv(t->tm_hour, 2, '0');
- X continue;
- X case 'I':
- X _conv(t->tm_hour % 12 ?
- X t->tm_hour % 12 : 12, 2, '0');
- X continue;
- X case 'j':
- X _conv(t->tm_yday + 1, 3, '0');
- X continue;
- X case 'k':
- X _conv(t->tm_hour % 12 ?
- X t->tm_hour % 12 : 12, 2, ' ');
- X continue;
- X#ifdef KITCHEN_SINK
- X case 'K':
- X _add("kitchen sink");
- X continue;
- X#endif /* defined KITCHEN_SINK */
- X case 'l':
- X _conv(t->tm_hour, 2, ' ');
- X continue;
- X case 'M':
- X _conv(t->tm_min, 2, '0');
- X continue;
- X case 'm':
- X _conv(t->tm_mon + 1, 2, '0');
- X continue;
- X case 'n':
- X _add("\n");
- X continue;
- X case 'p':
- X _add(t->tm_hour >= 12 ? "PM" : "AM");
- X continue;
- X case 'R':
- X _fmt("%H:%M", t);
- X continue;
- X case 'r':
- X _fmt("%I:%M:%S %p", t);
- X continue;
- X case 'S':
- X _conv(t->tm_sec, 2, '0');
- X continue;
- X case 'T':
- X case 'X':
- X _fmt("%H:%M:%S", t);
- X continue;
- X case 't':
- X _add("\t");
- X continue;
- X case 'U':
- X _conv((t->tm_yday + 7 - t->tm_wday) / 7,
- X 2, '0');
- X continue;
- X case 'W':
- X _conv((t->tm_yday + 7 -
- X (t->tm_wday ? (t->tm_wday - 1) : 6))
- X / 7, 2, '0');
- X continue;
- X case 'w':
- X _conv(t->tm_wday, 1, '0');
- X continue;
- X case 'y':
- X _conv((t->tm_year + TM_YEAR_BASE) % 100,
- X 2, '0');
- X continue;
- X case 'Y':
- X _conv(t->tm_year + TM_YEAR_BASE, 4, '0');
- X continue;
- X case 'Z':
- X#ifdef TM_ZONE
- X if (t->TM_ZONE)
- X _add(t->TM_ZONE);
- X else
- X#endif /* defined TM_ZONE */
- X if (t->tm_isdst == 0 || t->tm_isdst == 1) {
- X extern char * tzname[2];
- X
- X _add(tzname[t->tm_isdst]);
- X } else _add("?");
- X continue;
- X case '%':
- X /*
- X * X311J/88-090 (4.12.3.5): if conversion char is
- X * undefined, behavior is undefined. Print out the
- X * character itself as printf(3) also does.
- X */
- X default:
- X break;
- X }
- X if (gsize <= 0)
- X return;
- X *pt++ = *format;
- X --gsize;
- X }
- X}
- X
- Xstatic void
- X_conv(n, digits, fill)
- X int n, digits, fill;
- X{
- X static char buf[10];
- X register char *p;
- X
- X for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
- X *p-- = n % 10 + '0';
- X while (p > buf && digits-- > 0)
- X *p-- = fill;
- X _add(++p);
- X}
- X
- Xstatic void
- X_add(str)
- X register char *str;
- X{
- X for (;; ++pt, --gsize) {
- X if (gsize <= 0)
- X return;
- X if (!(*pt = *str++))
- X return;
- X }
- X}
- X
- *-*-END-of-src/strftime.c-*-*
- echo x - src/sysmail.c
- sed 's/^X//' >src/sysmail.c <<'*-*-END-of-src/sysmail.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | SYSTEM MAILING ROUTINES |
- X | |
- X | Version 2.7 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X ----------------------------------------------------------------------------
- X
- X These routines implement the 'system' mailmethod. The system opens a socket
- X and connects directly with sendmail for mail delivery. During the process
- X of porting the code to various platforms, lots of grosse things were
- X encountered with sockets and protocols, so the code may seem kludgy.
- X
- X When mail cannot be sent due to network problems, it is queued up and will
- X be delivered later by the queue daemon.
- X*/
- X
- X#include <stdio.h>
- X#include <string.h>
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include "defs.h"
- X#include "struct.h"
- X#include "sysmail.h"
- X#ifdef TCP_IP
- X# include <fcntl.h>
- X# include <errno.h>
- X# ifdef unknown_port
- Xextern int errno;
- X# endif
- X# include <sys/socket.h>
- X# include <netinet/in.h>
- X# include <netdb.h>
- X# if (defined (sco) || defined (M_XENIX) || defined (M_UNIX)) && \
- X defined (HAVE_SELECT_H)
- X# include <sys/times.h>
- X# else
- X# include <sys/time.h>
- X# endif
- X# ifdef HAVE_SELECT_H
- X# include <sys/select.h>
- X# endif
- X# ifdef HAVE_ULIMIT_H
- X# include <ulimit.h>
- X# endif
- X# ifndef UL_GDESLIM
- X# define UL_GDESLIM 4
- X# endif
- X# ifndef FD_SET /* for 4.2BSD */
- X# define FD_SETSIZE (sizeof(fd_set) * 8)
- X# define FD_SET(n, p) (((fd_set *) (p))->fds_bits[0] |= (1 << ((n) % 32)))
- X# define FD_CLR(n, p) (((fd_set *) (p))->fds_bits[0] &= ~(1 << ((n) % 32)))
- X# define FD_ISSET(n, p) (((fd_set *) (p))->fds_bits[0] & (1 << ((n) % 32)))
- X# define FD_ZERO(p) memset ((char *)(p), '\0', sizeof(*(p)))
- X# endif
- X#endif
- X
- X#ifdef __STDC__
- X# include <stdarg.h>
- Xextern int syscom (char *, ...);
- Xextern char *tsprintf (char *, ...);
- X#else
- X# include <varargs.h>
- Xextern int syscom ();
- Xextern char *tsprintf ();
- X#endif
- Xextern FILE *report;
- Xextern SYS sys;
- Xextern BOOLEAN debug;
- Xextern int listid;
- X
- X#ifndef __NeXT__
- Xextern long int atoi (char *);
- X#else
- Xextern int atoi (const char *);
- X#endif
- Xextern void report_progress (FILE *, char *, int);
- Xextern int gexit (int);
- Xextern int echo (char *, char *);
- Xextern int mv (char *, char *);
- X
- XBOOLEAN sysmail (char *);
- X#ifdef TCP_IP
- XBOOLEAN _sysmail (char *, int);
- Xint server_response (int);
- Xint build_tcp_connection (FILE *);
- Xvoid queue_up (char *file);
- X#endif
- X
- X/*
- X The return value depends on the return value of _sysmail ().
- X*/
- X
- XBOOLEAN sysmail (char *file)
- X{
- X#ifdef TCP_IP
- X queue = FALSE;
- X if (debug) {
- X OPEN_FILE (sent, SENT, "w", "sysmail");
- X OPEN_FILE (received, RECEIVED_, "w", "sysmail");
- X }
- X return _sysmail (file, 1);
- X#endif
- X}
- X#ifdef TCP_IP
- X
- X/*
- X 'system' mailmethod. It returns TRUE if the mail was successfully
- X delivered, FALSE if it was queued.
- X*/
- X
- XBOOLEAN _sysmail (char *file, int call)
- X{
- X char buf [MAX_LINE] ;
- X FILE *msg;
- X int sock_fd, cmd, bytes_to_write, bytes_written, i;
- X
- X OPEN_FILE (msg, file, "r", "_sysmail");
- X if ((sock_fd = build_tcp_connection (report)) < 0) {
- X queue = TRUE;
- X goto abort;
- X }
- X if ((cmd = server_response (sock_fd)) != ACKNOWLEDGE) {
- X report_progress (report, "\n_sysmail(): Could not connect to sendmail",
- X TRUE);
- X queue = TRUE;
- X goto abort;
- X }
- X
- X PROTOCOL (DATA);
- X while (!feof (msg) && strcmp (buf, END_OF_TEXT)) { /* Copy header and text */
- X RESET (buf);
- X fgets (buf, MAX_LINE - 2, msg);
- X WRITE_TO_SOCKET (sock_fd, buf);
- X }
- X cmd = server_response (sock_fd);
- X CHECK_SERVER_RESPONSE (cmd, OK, NULL);
- X PROTOCOL (CLOSE_CONNECTION);
- X
- X abort:
- X if (queue)
- X queue_up (file);
- X CLOSEF;
- X if (debug)
- X fclose (sent),
- X fclose (received);
- X return !queue;
- X}
- X
- X/*
- X Get server response. Return the command number that sendmail sent,
- X CONN_TIMEOUT or HOST_ABORTED.
- X*/
- X
- Xint server_response (int sock_fd)
- X{
- X char buf [MAX_LINE];
- X long int cmd, i, column = 3, bytes_to_read = 3, bytes_read = 0;
- X int nfds, value;
- X BOOLEAN done = FALSE, continued = FALSE;
- X fd_set rfds;
- X struct timeval timeout;
- X
- X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
- X defined (apollo) || defined (unknown_port)
- X nfds = getdtablesize ();
- X# else
- X nfds = ulimit (UL_GDESLIM);
- X# endif
- X RESET (buf);
- X while (bytes_to_read) {
- X /* Get server command */
- X FD_ZERO (&rfds);
- X do {
- X FD_SET (sock_fd, &rfds);
- X timeout.tv_sec = timeout.tv_usec = TIMEOUT;
- X errno = 0;
- X value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
- X } while (value == -1 && errno == EINTR);
- X
- X if (value == 0)
- X return CONN_TIMEOUT;
- X else if (value < 0) {
- X report_progress (report, tsprintf ("\nserver_response: select() failed;\
- X errno %d\n", errno), TRUE);
- X return -1; /* = CONN_TIMEOUT */
- X }
- X
- X errno = 0;
- X if ((bytes_read = read (sock_fd, &buf [3 - bytes_to_read], bytes_to_read))
- X < 0)
- X if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
- X errno == ECONNREFUSED)
- X return HOST_ABORTED;
- X if (bytes_read > 0)
- X bytes_to_read -= bytes_read;
- X }
- X RESET (message);
- X buf[3] = EOS;
- X cmd = atoi (buf);
- X sprintf (message, "%s", buf);
- X i = strlen (message);
- X if (debug)
- X fprintf (received, "%s", buf),
- X fflush (received);
- X while (!done) { /* Read till the end of socket */
- X FD_ZERO (&rfds);
- X do {
- X FD_SET (sock_fd, &rfds);
- X timeout.tv_sec = timeout.tv_usec = TIMEOUT;
- X errno = 0;
- X value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
- X } while (value == -1 && errno == EINTR);
- X
- X if (value == 0)
- X return CONN_TIMEOUT;
- X else if (value < 0) {
- X report_progress (report, tsprintf ("\nserver_response: select() failed;\
- X errno %d\n", errno), TRUE);
- X return -1; /* = CONN_TIMEOUT */
- X }
- X
- X errno = 0;
- X if ((bytes_read = read (sock_fd, buf, 1)) < 1)
- X if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
- X errno == ECONNREFUSED)
- X return HOST_ABORTED;
- X if (bytes_read > 0) {
- X ++column;
- X if (buf[0] == '\n') {
- X column = 0;
- X if (!continued)
- X done = TRUE;
- X }
- X if (column == 4)
- X if (buf[0] != '-')
- X continued = FALSE;
- X else
- X continued = TRUE;
- X message [i++] = buf[0];
- X if (debug)
- X fprintf (received, "%c", buf[0]),
- X fflush (received);
- X }
- X }
- X message [i] = EOS;
- X return cmd;
- X}
- X
- X/*
- X Establish connection with sendmail/smtp.
- X*/
- X
- Xint build_tcp_connection (FILE *report)
- X{
- X int sock_fd;
- X struct sockaddr_in sin;
- X struct hostent *hostentry;
- X
- X if (! (hostentry = gethostbyname (SENDMAIL_HOST))) {
- X report_progress (report, "\nbuild_tcp_connection(): No such host", TRUE);
- X return -1;
- X }
- X if ((sock_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
- X report_progress (report, "\nbuild_tcp_connection(): Could not create \
- Xsocket", TRUE);
- X return -1;
- X }
- X sin.sin_family = AF_INET;
- X sin.sin_port = htons (PORT);
- X memcpy ((char *) &sin.sin_addr.s_addr, (char *) hostentry->h_addr,
- X hostentry->h_length);
- X memset (sin.sin_zero, EOS, sizeof (sin.sin_zero));
- X if (connect (sock_fd, (struct sockaddr *) &sin, sizeof (struct sockaddr_in))
- X < 0) {
- X report_progress (report, "\nbuild_tcp_connection(): Could not connect to \
- Xport", TRUE);
- X close (sock_fd);
- X return -1;
- X }
- X# ifdef NONBLOCKING_IO
- X if (fcntl (sock_fd, F_SETFL, (fcntl (sock_fd, F_GETFL, 0) | O_NDELAY)) < 0)
- X report_progress (report, "\nbuild_tcp_connection(): WARNING: timeout \
- Xmechanism not functional", TRUE);
- X# endif
- X return sock_fd;
- X}
- X
- X/*
- X Queue up a file for later delivery.
- X*/
- X
- Xvoid queue_up (char *file)
- X{
- X FILE *id;
- X int id_no = 0;
- X char msg [MAX_LINE];
- X
- X if ((id = fopen (IDF, "r")) != NULL)
- X fscanf (id, "%d\n", &id_no),
- X fclose (id);
- X mv (file, tsprintf ("%s/%d", QUEUE_DIR, ++id_no));
- X echo (tsprintf ("%d", id_no), IDF);
- X sprintf (msg, "File %s placed in the mail queue", file);
- X report_progress (report, msg, TRUE);
- X}
- X#endif
- *-*-END-of-src/sysmail.c-*-*
- echo x - src/tlock.c
- sed 's/^X//' >src/tlock.c <<'*-*-END-of-src/tlock.c-*-*'
- X/*
- X ----------------------------------------------------------------------------
- X | tlock UTILITY |
- X | |
- X | Version 2.1 |
- X | |
- X | (or, when Computer Science gets to you) |
- X | |
- X | Written by Anastasios Kotsikonas |
- X | (tasos@cs.bu.edu) |
- X | |
- X | AGREEMENT: This software can be used and distributed freely only as a |
- X | whole and not in parts, as long as you do not remove or alter the author |
- X | and copyright notices in the file defs.h; this notices are #define'd in |
- X | the symbols VERSION and COPYRIGHT. Although you may alter the code |
- X | provided for your personal use, you may not alter the functions |
- X | create_header(), create_multi_recipient_header() and main() in list.c, |
- X | listproc.c and serverd.c (where applicable), and you may not redistribute|
- X | any changes you may have made. No part of the source code bearing a |
- X | copyright notice can be included in commercial software systems without |
- X | written permission by the author. |
- X | By using this software you are bound by this agreement. |
- X | This software comes with no warranties and cannot be sold for profit. |
- X | The AGREEMENT and COPYRIGHT notices should be included in all source |
- X | files when distributing this software. |
- X | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas |
- X | Use, duplication or disclosure by the Federal Government is subject to |
- X | the restrictions set forth in FAR 52.227-19(c), Commercial Computer |
- X | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
- X | (ii). |
- X | |
- X | Enhanced by: Warren Burstein. |
- X ----------------------------------------------------------------------------
- X*/
- X
- X#include <stdio.h>
- X#include <string.h>
- X#ifndef unknown_port
- X# ifndef __NeXT__
- X# include <unistd.h>
- X# else
- X# include <libc.h>
- X# endif
- X#endif
- X#include <fcntl.h>
- X#include <errno.h>
- X#ifdef unknown_port
- Xextern int errno;
- X#endif
- X#include "defs.h"
- X#include "struct.h" /* global.h needs it */
- X#include "global.h" /* misc.c needs it */
- X
- XBOOLEAN tty_echo = TRUE; /* ditto */
- XFILE *report = NULL; /* ditto */
- Xint sid = -1;
- X
- Xextern void setup_string (char *, char *, char *);
- Xextern char *locase (char *);
- Xextern char *upcase (char *);
- X
- Xvoid main ();
- Xint check (char *);
- Xint gexit (int);
- X
- Xvoid main ();
- X
- Xchar *s[] = {
- X SERVERD_LOCK_FILE, PQUEUE_LOCK_FILE, SERVER_MAIL_FILE, BATCH_FILE, NULL
- X};
- X
- X/*
- X Test whether any locks exist on the above files plus the mail and moderated
- X files of each list by other processes.
- X
- X USER CONTRIBUTED MODIFIED CODE: Warren Burstein.
- X*/
- X
- Xvoid main ()
- X{
- X#ifndef NO_LOCKS
- X char cmd[MAX_LINE], args[MAX_LINE], file[MAX_LINE], alias[MAX_LINE];
- X int i, locks = 0;
- X FILE *fp;
- X
- X for (i = 0; s[i]; i++)
- X locks += check (s[i]);
- X
- X if ((fp = fopen (CONFIG, "r")) == NULL) {
- X fprintf (stderr, "Cannot open %s\n", CONFIG);
- X gexit (1);
- X }
- X
- X while (! feof (fp)) {
- X args [0] = RESET (cmd);
- X fscanf (fp, "%s", cmd);
- X if (cmd[0] == EOS)
- X continue;
- X fgets (args, MAX_LINE - 2, fp);
- X if (args [0] != EOS && args [strlen (args) - 1] == '\n')
- X args [strlen (args) - 1] = EOS;
- X
- X if (strcmp (locase (cmd), "list") == 0 && sscanf (args, "%s", alias) == 1)
- X upcase (alias),
- X setup_string (file, alias, LIST_MAIL_FILE),
- X locks += check (file),
- X setup_string (file, alias, LIST_MODERATED_F),
- X locks += check (file);
- X }
- X fclose(fp);
- X
- X if (!locks)
- X printf ("No files locked.\n"),
- X gexit (0);
- X gexit (locks + 1);
- X#else
- X printf ("File locking mechanism not functional. This mechanism is turned off \
- Xusually when\nfile locking is not supported over NFS. If this system is \
- Xinstalled on a local\nfile system, you may consider undefining the symbol \
- XNO_LOCKS in src/defs.h;\ncheck also with your system manuals to verify that \
- Xfile locking over NFS is\nindeed not supported.\n");
- X gexit (-1);
- X#endif
- X}
- X
- X/*
- X Check whether a file is locked.
- X
- X USER CONTRIBUTED FUNCTION: Warren Burnstein.
- X*/
- X
- Xint check (char *s)
- X{
- X#ifndef NO_LOCKS
- X int fd, ret = 0;
- X
- X if (lockf ((fd = open (s, O_RDWR)), F_TLOCK, 0))
- X if (errno != EBADF)
- X ret = 1,
- X printf ("Lock placed on %s\n", s);
- X close (fd);
- X return ret;
- X#endif
- X}
- X
- X/*
- X Required to avoid undefined symbols.
- X*/
- X
- Xint gexit (int exitcode)
- X{
- X exit (exitcode);
- X}
- *-*-END-of-src/tlock.c-*-*
- echo x - doc/README
- sed 's/^X//' >doc/README <<'*-*-END-of-doc/README-*-*'
- X
- XTo install the man pages permanently on your system you will need to do the
- Xfollowing as superuser:
- X
- X% cp *.nr /usr/man/cat1 <- or wherever the man pages are
- X% cd /usr/man/cat1
- X% compress *.nr
- X% mv server.nr.Z server.1
- X% mv farch.nr.Z farch.1
- X% mv queue.nr.Z queue.1
- X% mv catmail.nr.Z catmail.1
- X% mv list.nr.Z list.1
- X% mv listproc.nr.Z listproc.1
- X% mv serverd.nr.Z serverd.1
- X% mv start.nr.Z start.1
- X% mv ilp.nr.Z ilp.1
- X% chmod 444 server.1 farch.1 queue.1 catmail.1 list.1 listproc.1 serverd.1 \
- X start.1 ilp.1
- X% vi Index <--- if availbable
- X add the following lines in Index in the appropriate alphabetic location:
- X server.1:server:
- X farch.1:farch:
- X queue.1:queue:
- X catmail.1:catmail:
- X list.1:list:
- X listproc.1:listproc:
- X serverd.1:serverd:
- X start.1:start:
- X ilp.1:ilp:
- X% vi /usr/man/whatis <-- or whatever file is used when doing man -k
- X add the following lines in whatis:
- X server(1) - ListProcessor system description
- X farch(1) - ListProcessor file archiving utility
- X queue(1) - ListProcessor mail queue processing
- X catmail(1) - ListProcessor mail redirection
- X list(1) - ListProcessor mailing list processing
- X listproc(1) - ListProcessor request processing
- X serverd(1) - ListProcessor system daemon
- X start(1) - ListProcessor housekeeper
- X ilp(1) - Interactive ListProcessor client
- X
- *-*-END-of-doc/README-*-*
- echo x - doc/catmail.1
- sed 's/^X//' >doc/catmail.1 <<'*-*-END-of-doc/catmail.1-*-*'
- X.\" ListProcessor System
- X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
- X.\"
- X.TH catmail 1 "ListProcessor"
- X.SH NAME
- X\fBcatmail\fP \- append incoming mail to ListProcessor system files
- X.SH SYNOPSIS
- X\fBcatmail\fP {<\fB-L LIST_ALIAS\fP [\fB-m\fP]> | <\fB-r\fP>} [\fB-f\fP]
- X.SH DESCRIPTION
- X\fIcatmail\fP is used to redirect incoming mail to the ListProcessor system
- Xto the appropriate
- Xfiles, according to the flags specified. The files affected are
- XHOMEDIR/requests (a repository for requests), HOMEDIR/lists/*/mail
- X(public messages to be distributed) and HOMEDIR/lists/*/moderated
- X(messages to be screened out by a moderator). \fIcatmail\fP reports the
- Xuser id and user name that is currently executing it; the setuid bit
- Xhas to be set when installed. \fIcatmail\fP first locks the output file
- Xbefore appending to it; if the file cannot be locked after 3 minutes, the
- Xmail is saved under HOMEDIR/lost+found or HOMEDIR/lists/*/lost+found;
- Xboth \fIlist\fP and \fIlistproc\fP
- Xlock their mail files while copying them to a safe place. \fIcatmail\fP will
- Xtime out after 2 minutes to avoid deadlock situations, and the mail message
- Xmay be returned to the sender as undeliverable.
- X.SH OPTIONS
- XThe following command line options are recognized:
- X.TP
- X-L LIST_ALIAS [-m]
- XIf the -m flag is not specified, append to
- XHOMEDIR/lists/\fILIST_ALIAS\fP/mail; otherwise append to
- XHOMEDIR/lists/\fILIST_ALIAS\fP/moderated (see \fIlist(1)\fP).
- X.TP
- X-r
- XAppend to HOMEDIR/requests (overrides -L).
- X.TP
- X-f
- XReformat the message in the process: all lines in the message except the first
- Xstarting with "From " are converted to ">From ".
- X(see also SYSTEM\ SETUP in \fIserver\fP(1)).
- X.SH SEE\ ALSO
- Xlist(1), listproc(1), server(1)
- X.SH AUTHOR
- X.nf
- XAnastasios C. Kotsikonas
- XCopyright (c) 1991-93, Anastasios Kotsikonas
- XComments to tasos@cs.bu.edu
- X.fi
- *-*-END-of-doc/catmail.1-*-*
- echo x - doc/farch.1
- sed 's/^X//' >doc/farch.1 <<'*-*-END-of-doc/farch.1-*-*'
- X.\" ListProcessor System
- X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
- X.\"
- X.TH farch 1 "ListProcessor"
- X.SH NAME
- X\fBfarch\fP \- archive files under the ListProcessor system
- X.SH SYNOPSIS
- X\fBfarch\fP {[\fB-n\fP] [\fB-b\fP | \fB-B\fP] [\fB-s\ size\fP] [\fB-d\ dir\fP] [\fB-p\ password\fP] [\fB-D\ description\fP]\ [\fB-t\ file\fP] [-u]} | {[\fB-r\fP]} [\fB-a\ archive | path-to-archive\fP] [\fB-Z\fP] <\fBfiles\fP>
- X.SH DESCRIPTION
- X\fIfarch\fP is used to archive files under the ListProcessor system
- Xor remove files already achived, with support provided for private archives.
- XArchives reside under HOMEDIR/archives as subdirectories; the default is
- X\fIlistproc\fP,
- Xand it is also the master archive. Archives are hierarchically
- Xstructured, and each archive has at least two files in its directory:
- X.TP
- XINDEX
- XA list of all subarchives including itself; the format is one line per
- Xarchive with the archive's name followed by the archive's full path, followed
- Xby an optional password:
- X.sp
- Xarchive-name full-path-to-archive-directory [password]
- X.sp
- XThe first entry should be the archive itself;
- Xeach first level subarchive is listed next; then each second level
- Xsubarchive, starting with the first first-level-archive's subarchives,
- Xfollowed by the second first-level-archive's subarchives, etc. No sibling
- Xarchives may have the same name, although there is no such restriction
- Xfor archives on different levels, or "cousin" archives. The latter archives
- Xare distinguished by the relative path needed to access them (see
- X\fIserver\fP(1) for more information).
- X.TP
- XDIR
- XA list of files available from that archive; the format is one line
- Xper file with the file name followed by the number of parts it may be
- Xsplit into, followed by the number of bytes of each of the parts, followed
- Xby the full path to the directory these parts can be found, followed
- Xby a short descriptive message about the file (optional). The descriptive
- Xmessage may span several lines; each line (except the last) should end
- Xwith a '\\':
- X.sp
- X.nf
- Xfile nparts size-of-each-part+ full-path-to-directory [description [\\]]
- X[multiple description lines [\\]]*
- X.fi
- X.sp
- XThe number of parts the file is split into may be -1 to indicate that
- Xthis is a binary file.
- X.PP
- X\fIfarch\fP reports on the action taken on each input file: whether it
- Xwas split (and how many parts), whether it was uuencoded, whether all files
- Xhave been tar'red into a single one, the archive this file was archived under,
- Xand the directory the output file(s) (if any) has/have been placed. It
- Xalso reports when the input files are tarred.
- X.SH OPTIONS
- XThe following command line options are recognized:
- X.TP
- X-n
- XDo not split files when archiving them. The default is to split them with
- Xeach part not larger than the specified size (see the -s option below).
- X.TP
- X-b
- XInput files are binary; they are uuencoded before archived.
- X.TP
- X-B
- XInput files are binary; they are neither uuencoded nor split.
- X.TP
- X-s size
- XSpecify the maximum \fIsize\fP in kilobytes of each of the subparts
- X(default is 64).
- X.TP
- X-d dir
- XSpecify the \fIdir\fPectory that the output files are to be placed; if
- Xleft out, it defaults to the specified archive's directory
- X(HOMEDIR/archives/listproc if the archive is left out as well).
- XIf the directory (and all of its subdirectories, if any) does not exist,
- Xit will be created.
- X.TP
- X-p password
- XWhen a new archive is to be created, and that archive is to be private,
- Xspecify the access password.
- X.TP
- X-D description
- XPut \fIdescription\fP (most likely surrounded by single quotes) in the
- XDIR file as explanatory comment about the archived file. This option does
- Xnot make much sense when archiving more than one file at the same time.
- X.TP
- X-t file
- XInput files are tar'red into \fIfile\fP which is then archived (the -b flag
- Xis automatically turned on). Turning on the -B flag will prevent uuencoding
- Xof the tar file. Note that whatever the path to \fIfile\fP may
- Xbe, it will be moved to the specified directory as specified by the -d flag.
- X.TP
- X-u
- XUpdate existing files while archiving; preserve the current comment fields,
- Xunless -D is explicitly used.
- X.TP
- X-r
- XRemove the specified file(s) from the specified archive (see below), or the
- Xdefault one; it has higher priority than all of the options above.
- X.TP
- X-a archive | path-to-archive
- XSpecify the \fIarchive\fP that the input files will be archived under (default
- Xis listproc). Archives on different levels of the hierarchy may have the
- Xsame name and in this case a \fIpath-to-archive\fP may be specified to
- Xdistinguish between them;
- X\fIpath-to-archive\fP has the form \fIarchive[/archive[/archive...]]\fP
- X(see also \fIserver(1)\fP). If any of the archives in the path do not exist,
- Xthey will be created with the necessary files.
- X.TP
- X-Z
- XTurn off file compression.
- X.PP
- XFile names in the DIR file have to be unique and \fIfarch\fP will not
- Xarchive duplicate files.
- X.SH ARCHIVING\ A\ FILE
- X\fIfarch\fP by default splits the input files if necessary
- X(or the tar file, if any),
- Xinto files of maximum size as specified. Each part
- Xwill contain as many complete lines from the original input file as possible,
- Xwithout exceeding the specified size. Binary files (including the tar file)
- Xare uuencoded before they are archived unless the -B option is specified,
- Xand all archived files are compressed, if possible.
- X.SH ADDING\ A\ NEW\ ARCHIVE
- X.TP
- Xautomatically
- XSimply specify the new archive as argument to the -a flag. All necessary DIR
- Xand INDEX files as well as all required directories will be created, and
- Xall parent archives will be updated.
- X.TP
- Xby hand
- XStep 1
- X.sp
- XCreate a directory under HOMEDIR/archives or under an existing
- Xarchive's directory (beware of the hierarchy structure), naming the
- Xdirectory after the archive.
- XThe archive's name should be unique among its siblings on that level in the
- Xhierarchy (besides, mkdir will not let specify a name that already exists).
- X.sp
- XStep 2
- X.sp
- XEdit the master archive's index file (HOMEDIR/archives/listproc/INDEX) and
- Xadd the new archive along with its path (and optional password -- see below)
- Xat the proper place in the file, making sure you adhere to the
- Xrules about hierarchy outined above. The first line of every INDEX
- Xfile should be the archive itself. Also edit (add to) every ancestor archive's
- XINDEX file, if the new archive is not the default, again making sure you adhere
- Xto the same rules.
- X.sp
- XStep 3
- X.sp
- XCreate a new INDEX file in the new archive's directory and put an entry
- Xfor itself.
- X.sp
- XStep 4
- X.sp
- XCreate an empty DIR file in the new archive's directory.
- X.SH PRIVATE\ ARCHIVES
- XPrivate archives are archives that require a password for obtaining
- Xindices and/or files from them. To make an archive private, simply
- Xappend a password (case does not matter) after its full path specification
- Xin every INDEX file the archive is defined (its own plus all ancestors' --
- Xthe same password has to be used in all of these files). Then, that
- Xpassword has
- Xto be made known to all users who are to be granted access to this archive.
- XNote that all files in the same private archive can be obtained with the
- Xsame single password.
- X.SH EXAMPLES
- XArchive src/data and src/data2 under archive listproc (the default),
- Xusing a maximum file size of 1K; the output file(s) will be placed in /tmp/tmp:
- X.sp
- X.nf
- X.in +2
- X% farch -s 1 -d /tmp/tmp src/data src/data2
- X.fi
- X.in -2
- X.sp
- XArchive /etc/hosts under archive unix (that is listproc/unix) -- the -n
- Xflag is used to avoid writing split parts to /etc which is doomed to fail:
- X.sp
- X.nf
- X.in +2
- X% farch -n -a unix -d /etc -p private /etc/hosts
- X.fi
- X.in -2
- X.sp
- XArchive /etc/password under archive pub/unix (that is listproc/pub/unix):
- X.sp
- X.nf
- X.in +2
- X% farch -n -a pub/unix -d /etc /etc/passwd
- X.fi
- X.in -2
- X.sp
- XTar and archive all files in /usr/src to the default archive and place the
- Xtar file under /tmp/tmp:
- X.sp
- X.nf
- X.in +2
- X% farch -t HOMEDIR/source -d /tmp/tmp /usr/src/*.c
- X.fi
- X.in -2
- X.sp
- XDescriptive messages about these files are added manually into the archive's
- XDIR file. However, the -D option can be used to specify a string as follows:
- X.sp
- X.nf
- X.in +2
- X% farch -D 'ListProcessor system files' -t ulistproc.tar -n -d /usr/server /usr/server/*
- X.SH UPGRADING
- XIf you are upgrading from:
- X.TP
- X5.5
- XThe -B, -p, -r and -D options are new; functionality is the same.
- X.TP
- X5.41 or less
- XEvery DIR file should now include the size of each of the parts of every
- Xfile, placed between the number of parts and the path name.
- X.sp
- XThe -a option has been extended to accept paths to archives.
- X.SH RESTRICTIONS
- X\-
- XArchive names and input files must use only lower case characters of the
- Xalphabet.
- X.SH WARNINGS
- X\-
- XInput files that are to be tar'red should only include relative path names;
- Xotherwise the end user may not be able to extract them.
- X.sp
- X\-
- XThe tar file should not be any of the input files.
- X.SH SEE\ ALSO
- Xserver(1)
- X.SH AUTHOR
- X.nf
- XAnastasios C. Kotsikonas
- XCopyright (c) 1991-93, Anastasios Kotsikonas
- XComments to tasos@cs.bu.edu
- X.fi
- *-*-END-of-doc/farch.1-*-*
- echo x - doc/ilp.1
- sed 's/^X//' >doc/ilp.1 <<'*-*-END-of-doc/ilp.1-*-*'
- X.\" ListProcessor System
- X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
- X.\"
- X.TH ilp 1 "ILP 2.1"
- X.SH NAME
- X\fBilp\fP \- Interactive ListProcessor client
- X.SH SYNOPSIS
- X\fBilp\fP [\fB-v\fP] [\fB-t timeout\fP] [\fB-b buffer-size in K\fP] \fBhost\fP [\fBport\fP]
- X.SH DESCRIPTION
- X\fIilp\fP is a client that connects to the specified \fIhost\fP's
- XInteractive ListProcessor port (372) for a live session -- i.e. for
- Xprocessing requests live. Another \fIport\fP
- Xmay be specified if necessary. The \fIhost\fP may be a host name, or an
- XIP address.
- X.PP
- XUpon connection establishment, the protocol attempts to set the user's
- Xprivileges during the session by requesting an email address and a password.
- XThese are used to determine whether the user is to be granted system,
- Xowner, subscriber or casual user privileges. If the user provides
- Xhis owner email address and his list's password, he will be granted
- Xowner privileges. If he provides an email address that he uses for subscription
- Xto a list, along with the password he uses for that list, he will be granted
- Xsubscriber privileges. The system provides a brief listing of all valid
- Xrequests the user may issue during the session. If no email address is
- Xprovided, or no matches are found, the user is restricted to a few
- Xrequests.
- X.PP
- XRequests for remote lists are serviced by attempting to connect
- Xto the ILP server(s) (if any) of the system(s) that handle those lists.
- X.PP
- XThe ILP server recognizes the following special requests:
- X.TP
- Xquit/exit
- XEnd the session.
- X.TP
- X?/privileges
- XGet a brief listing of all valid requests.
- X.TP
- Xtimeleft
- XPrints the remaining time in seconds.
- X.TP
- X&<new-line>
- XInput continues on the next line.
- X.TP
- Xbinary
- XSwitch to binary mode when transferring files.
- X.TP
- Xascii
- XSwitch to ASCII mode when transferring files.
- X.TP
- X< filename
- XInput is taken from the specified file. Each line will be interpreted as
- Xa separate request, unless the file is specified in conjunction with a
- X\fIput\fP request. If the '<' is to be used literally it
- Xmust be escaped with '\\' or enclosed in quotes.
- X.TP
- X> filename
- XRedirect the reply to the request to the specified file. Error messages
- X(such as rejections due to invalid requests, etc.) are not redirected.
- XWhen a file is downloaded via a \fIget\fP request, this will override the
- Xfile name that will be saved under. If the '>' is to be used literally it
- Xmust be escaped with \\ or enclosed in quotes.
- X.TP
- X>> filename
- XSame as above, but the reply is appended to the specified file.
- X.TP
- X| prog [args]
- XThe output of the request is piped to \fIprog\fP; this is similar to a
- XUNIX pipe. \fIprog\fP may be any valid UNIX command, including other pipes, file
- Xredirections, etc. Since '<' has higher precedence in this context, you
- Xshould escape any '<' characters intended to be used by the pipe, otherwise
- Xthe system will assume you are feeding it batched requests. Quotes may also
- Xbe used to protect these characters.
- X.SH OPTIONS
- XThe following options are recognized:
- X.TP
- X-v
- XTurn verbose mode on; the server reply codes are echoed along with
- Xpredetermined messages.
- X.TP
- X-t timeout
- XThe default time out for a server response is 180 seconds; to reset
- Xuse the -t flag. This timeout should not be confused with the
- Xremaining time of a connection.
- X.TP
- X-b buffer-size
- XThe default socket buffer size is 8K; to reset use the -b flag
- X(the argument specifies kilobytes).
- X
- X.SH USER\ PRIVILEGES
- XCasual users may only issue help, information, recipients and statistics
- Xfor nonprivate lists, lists, index, get, view, search and release requests.
- XSubscriber privileges also include the set, run, unsubscribe and which requests.
- XOwners may, in addition, issue all of their administrative requests.
- X.PP
- XIssue a 'help live' request when you first connect to an ILP server.
- X.SH RESTRICTIONS
- XThe connection duration is limited to a server-imposed limit.
- XAfter that, a connection may be broken by the server as necessary.
- XA connection will not be broken during a transfer.
- X.SH EXAMPLES
- X.nf
- Xrequest> put ermis ermis1 subscribers </usr/server/backup/lists/ERMIS/subs >out
- X.sp
- Xrequest> get listproc example.dat 1 3 >> out
- X.sp
- Xrequest> get listproc example.dat
- X.sp
- Xrequest> index ilp > ILP
- X.sp
- Xrequest> < /tmp/batched.requests
- X.sp
- Xrequest> index | more
- X.sp
- Xrequest> lists | cut -d ' ' -f1,2 | more
- X.sp
- Xrequest> search ilp "\\>\\> out"
- X.sp
- X.fi
- XIn this last example, we escape each > to protect it from being interpreted
- Xas a regular expression separator, and enclose the whole pattern in quotes
- Xto protect the \\>\\> from being evaluated.
- X.SH FILES
- X.TP
- Xilp.c, ilp.h
- XSource code for the client. See ilp.c for compile options.
- X.TP
- Xilpp.h
- XDefinition of the Interactive ListProcessor Protocol.
- X.TP
- Xmakefile
- Xmakefile to build \fIilp\fP. \fIilp\fP is written with BSD-style signal
- Xhandling, therefore on some hosts (like IBM AIX) you will have to link with
- XBSD versions of signal(2), socket(3N), and fcntl(2). Platforms that
- Xhave the <sys/select.h> and <ulimit.h> header files should compile
- Xwith -DHAVE_SELECT_H and/or -DHAVE_ULIMIT_H. SCO ports should compile with
- X-Dsco. Always link with libraries that provide DNS support (resolver linked
- Xin).
- X.SH BUGS
- XPlease report any bugs or enhancements to tasos@cs.bu.edu
- *-*-END-of-doc/ilp.1-*-*
- echo x - doc/list.1
- sed 's/^X//' >doc/list.1 <<'*-*-END-of-doc/list.1-*-*'
- X.\" ListProcessor System
- X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
- X.\"
- X.TH list 1 "ListProcessor"
- X.SH NAME
- X\fBlist\fP \- process a specified ListProcessor mailing list
- X.SH SYNOPSIS
- X\fBlist -L\fP\ <\fBLIST_ALIAS\fP> [\fB-1\fP] [\fB-e\fP] [\fB-s\fP] [\fB-p\fP] [\fB-P\fP] [\fB-m\ #\fP] [\fB-f\fP] [\fB-r\fP] [\fB-M\fP] [\fB-d\fP] [\fB-i\fP <\fBaddress\fP>] [\fB-v\fP] [\fB-Z\fP] [\fB-D\fP]
- X.SH DESCRIPTION:
- X\fIlist\fP distributes the message(s) sent to \fIlist_alias@your-domain\fP;
- Xthe file ".ignored" in the list's subdirectory is used to filter out any
- Xunwanted messages (see below).
- X.PP
- XMessages from mailer daemons are forwarded to the list's owner and screened
- Xlooking for delivery errors (in which case appropriate action is taken --
- Xusers are either immediately removed from the list, or after a series of
- Xdelivery errors within a certain time frame -- entries removed from the
- Xsystem's files are placed into HOMEDIR/lists/*/removed.users and
- XHOMEDIR/lists/*/removed.alias files),
- Xwhereas messages
- Xfrom non-subscribers are returned to the original senders (the -f flag
- Xoverrides this). Messages whose first line looks like a ListProcessor request
- Xare bounced back to the sender.
- X.PP
- XMessages from news groups are distributed only to local
- Xsubscribers and peer lists. Messages from peers are distributed to local
- Xsubscribers and possibly posted to news groups. Finally, messages from
- Xlocal subscribers are either distributed locally, copies are sent to all peers,
- Xand are possibly posted to news groups, or are forwarded to the list's
- Xowner for screening if the list is moderated.
- X.PP
- XAll distributed messages
- X(i.e. legitimate messages from subscribers, peers and news groups -- not
- Xrejected, ignored or error messages)
- Xare automatically archived in HOMEDIR/lists/*/archive. In contrast,
- Xthe files HOMEDIR/lists/*/mbox contain all messages sent to these
- Xlists (including, error, rejected and ignored messages).
- X.PP
- XEmail from one or more subscribers may be selectively distributed to an
- Xalternate list of recipients, by way of restricted mail (see below),
- Xin which case mail will not be distributed to the regular subscribers.
- X.PP
- XWhen the system is for some reason aborted while making a delivery, a
- Xbuilt-in mechanism allows it to resume from the point it left off.
- X.SH OPTIONS
- XThe following command line options are recognized:
- X.TP
- X-L LIST_ALIAS
- XProcess any messages sent to this \fILIST_ALIAS\fP -- \fILIST_ALIAS\fP should
- Xbe in capital letters.
- X.TP
- X-1
- XExecute only once; process the mailing list and return control to
- X\fIserverd\fP(1); any new messages that may have arrived in the meantime will
- Xbe processed at a later time. Without this option, \fIlist\fP will be
- Xlistening for messages for the specified list for ever. \fIserverd\fP(1)
- Xuses this option by default when spawning \fIlist\fP.
- X.TP
- X-e
- XEcho reports to the screen; it has no effect if the system has been compiled
- Xwith -DSYSLOG.
- X.TP
- X-s
- XBy default, only subscribers can send messages to a list. This option
- Xturns off subscription checking.
- X.TP
- X-p
- XBy default, replies to messages posted to news groups go to the list;
- Xthis option forces replies to be forwarded to the original author.
- X.TP
- X-P
- XBy default, replies to messages sent to subscribers and peers go to the
- Xlist; this option forces replies to be forwarded to the original author.
- X.TP
- X-m number
- XNormally, each outgoing message has one recipient. This flag switches to
- Xmulti-recipient outgoing messages and specifies the \fInumber\fP of recipients
- Xto be included in these messages.
- X.TP
- X-f
- XForward any messages from non-subscribers to the list's owner. By default,
- Xthey are returned to the sender.
- X.TP
- X-r
- XRestricted mail: \fIlist\fP will look at the ".restricted" file (see
- Xbelow) to get the name of the alternate recipients file. If the sender
- Xis listed in that ".restricted" file, his messages will be distributed
- Xto users listed in the alternate recipients file.
- X.TP
- X-M
- XThe list is moderated;
- Xall incoming messages not from the owner(s) are forwarded to the
- Xlist's primary owner for review and editing. The owner then sends back the
- Xones that are approved for posting (for an alternate scheme see the
- XMODERATED\ LISTS section below).
- X.TP
- X-d
- XForce a digest to be distributed. This flag is internally used by
- X\fIserverd\fP(1) when digest time has been reached for this list.
- X.TP
- X-i address
- XSend a partial digest to \fIaddress\fP (what has accumulated so far).
- XThis flag is internally used by
- X\fIlistproc\fP(1) when the user identified by \fIaddress\fP changes his
- X\fImail\fP mode from \fIdigest\fP to something else. Note that when
- Xthe time arrives for the current digest to be distributed, this
- Xuser will get duplicate messages.
- X.TP
- X-v
- XPrint version information.
- X.TP
- X-Z
- XTurn off file compression when archiving messages.
- X.TP
- X-D
- XTurns debugging on. When the \fIsystem\fP mailmethod is used (see \fIserver(1)\fP), a
- Xcopy of the last SMTP transaction can be found in the files
- XHOMEDIR/sent and HOMEDIR/received.
- X.SH ADDING\ A\ NEW\ LIST
- XTo add a new list, first shut the system down by executing \fIstart\fP(1):
- X.sp
- X.in +2
- X\fI% start -k\fP
- X.in -2
- X.sp
- XThen edit the \fIconfig\fP file and add a line defining the
- Xnew list -- you may wish to add a comment and/or disable a few requests also.
- XA new alias has to be set up in /etc/aliases, /usr/lib/aliases
- Xor /usr/ucblib/aliases of the following form:
- X.nf
- X.sp
- Xlist_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f"
- X.sp
- X.fi
- XIf using surrogate mail, then the alias is defined as follows in
- X/etc/mail/mailsurr:
- X.sp
- X.nf
- X\'.+' 'list_alias' '<S=0;F=1-255;C=*;HOMEDIR/catmail -L LIST_ALIAS -f'
- X.sp
- X.fi
- XNote that \fIlist_alias\fP is all lower case and \fILIST_ALIAS\fP is all
- Xupper case. In this case \fIcatmail\fP(1) appends incoming mail to the list's
- Xmail file (HOMEDIR/lists/LIST_ALIAS/mail).
- XAlso keep in mind the case of reformatting messages as described in
- X\fIcatmail\fP(1).
- X.PP
- XFinally, restart the system. At this point, the file ".ignored" in the
- XHOMEDIR/lists/LIST_ALIAS directory may be edited to add more
- Xunwanted senders. You should also edit the files ".welcome" and ".info"
- Xin the list's subdirectory; the former is included in the return message
- Xfor a new subscription request for that list, and the latter
- Xis included in the return message for an \fIinformation\fP request for that
- Xlist (see \fIlistproc\fP(1)). These files may be simple text files, or shell
- Xscripts (see the HELP section in \fIserver(1)\fP).
- X.SH ADDING\ A\ PEER\ LIST
- XPeer lists are mailing lists that happen to be subscribers to one
- Xor more of your own mailing lists; they handle local distribution of
- Xmessages just like you do at your own site. Peer lists can be mutual
- Xsubscribers, so that a message originating in a peer list gets distributed
- Xover there locally, and a copy is sent to the other for local distribution,
- Xand vice versa. An automatic mechanism is provided for avoiding loops.
- XA peer list can be added to
- Xa local mailing list by using the script \fIpeer\fP:
- X.sp
- Xpeer\ <LIST_ALIAS>\ <remote\ alias>\ <peer\ address>\ <remote\ ListProcessor\ address>
- X.sp
- Xwhere \fILIST_ALIAS\fP is a local list alias in capital letters,
- X\fIremote\ alias\fP is the peer's alias on the remote machine,
- X\fIpeer\ address\fP is taken
- Xfrom the first line of the header of a test message sent to your host
- Xby the peer
- X(the first line may be something like: "From peer@other-domain" -- see also
- Xthe discussion about aliases below), and
- X\fIremote\ ListProcessor\ address\fP is the full email address of the
- Xremote request-handler.
- X.PP
- XHere is an example for
- Xestablishing connection between two peer lists a@domain1 and b@domain2:
- XThe \fImanager\fP at domain1 issues the following command:
- X.sp
- X.nf
- Xpeer a b b@domain2 listproc@hdomain2
- X.fi
- X.sp
- XThe \fImanager\fP at domain2 issues the following command:
- X.sp
- X.nf
- Xpeer b a a@domain1 listproc@domain1
- X.fi
- X.sp
- XOnce these two commands are issued the connection is automatically
- Xset up.
- XPeer lists should make sure that only one of them posts
- Xto the same news group(s), and that only one of them receives articles
- Xfrom the same news group(s)/gateway(s).
- XLists handled by the same server cannot be mutual
- Xpeers. Finally, peer lists should not be regular subscribers (the
- X\fIpeer\fP script places them in a file called ".peers").
- X.SH NEWS\ GROUPS\ AND\ GATEWAYS
- XA mailing list may be linked with one or more news groups (or gateways)
- Xfrom which
- Xit may receive messages for local distribution, and/or send messages to
- Xthe newsgroup(s) for posting \-\- in this case only messages from
- Xregular subscribers and peers are sent for posting, i.e. no news messages
- Xwill be posted to any news groups (or gateways).
- XA news group or gateway is linked using the script \fInews\fP:
- X.sp
- X.ce
- Xnews\ <LIST_ALIAS>\ <news\ group>\ <email\ address>\ <mode>
- X.sp
- Xwhere \fILIST_ALIAS\fP is a local list alias (in capital letters)
- Xthat is being linked to the news group, \fInews\ group\fP is the name
- Xof the news group (used only when posting) e.g. misc.test,
- X\fIemail\ address\fP is the address of the backbone or moderator of
- Xthe news group, or the gateway, and it is taken
- Xfrom the first line of the header of a test message sent to your host
- Xby the group (the first line may be something like:
- X"From gateway@foo ..." -- see also the discussion about aliases below);
- X\fImode\fP is one of the following:
- X.TP
- Xreceive
- XThe list will only be receiving messages from this news group and never
- Xpost to it. This allows access to the group (or gateway)
- Xto send articles to the list.
- X.TP
- Xsend_receive
- XThe list may be receiving messages from this news group, and it will post
- Xto it any messages from regular subscribers and peer lists (messages from
- Xnews groups are never posted to other news groups). This also
- Xallows access to the group (or gateway) to send articles to the list.
- X.PP
- XOf course, the news group's
- Xcaretaker has to be notified of the list's address so that articles will indeed
- Xbe sent to it. Finally, news groups should not be regular subscribers (the
- X\fInews\fP script places them in a file called ".news").
- X.PP
- XIf the config option \fIpost_mail\fP is used,
- Xthe system will use \fIinews\fP for posting, and it assumes that the
- Xpath to it is /usr/lib/news/inews, so make sure that \fIinews\fP resides there,
- Xor a link exists to it. In this case, the group's name is used for posting
- X(e.g. misc.test). If instead \fIgate_mail\fP is defined, messages will
- Xbe sent via email to news gateways (using the \fIemail\ address\fP)
- X-- the \fInews\ group\fP name has no significance in this case.
- X.SH MODERATED\ LISTS
- XThe system supports two schemes for moderating lists. The first scheme uses
- Xthe -M flag to \fIlist\fP(1), and in this case messages not from the
- Xlist's owner(s) are forwarded to the list's primary owner for review;
- Xthe owner then sends back the approved (and possibly edited) ones.
- X.PP
- XThe second scheme uses the -m flag to \fIcatmail\fP(1). In this case, the
- Xlist's alias is changed slightly in the aliases file:
- X.nf
- X.sp
- Xlist_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f -m"
- X.sp
- X.fi
- Xand similarly if using surrogate mail.
- X\fIlist\fP(1) distributes messages from a file called \fImail\fP; by having
- Xincoming messages redirected to the file \fImoderated\fP (the effect of the
- X-m flag to \fIcatmail\fP(1)), the list's owner may \fIapprove\fP or
- X\fIdiscard\fP any number of these messages (see \fIlistproc\fP(1)).
- XWhenever a new
- Xmail message arrives for a moderated list, a copy is sent to the list's
- Xowner with instructions for approving or discarding it. These instructions
- Xinclude a unique tag number for identifying that message. When a message
- Xis approved, it is transferred to the \fImail\fP file for later delivery,
- Xand when discarded, it is simply removed from the
- X\fImoderated\fP file. This scheme cuts down on mail traffic.
- X.SH RESTRICTED\ MAIL
- XWhen the -r flag is used with \fIlist\fP(1), for every message received its
- Xsender is checked against a list of "restricted" email addresses, in the
- Xfile ".restricted" in the list's directory -- a
- Xsubset of the ".subscribers" file. If a match is found, mail is
- Xforwarded to the people listed in the file following this email
- Xaddress. If no match is found, the message is distributed to the
- Xregular subscribers. Note that the alternate recipients file should
- Xbe in the same format as the ".subscribers".
- X.SH .SUBSCRIBERS
- XThe format is as follows:
- X.PP
- XOne entry per line; each entry is the full email address of the subscriber
- Xas it appears in the "From " field, followed by the word "ACK" (in which
- Xcase his/her message will be sent back to him/her as an acknowledgement),
- X"NOACK" (the opposite), "POSTPONE" (no mail will be sent until the
- Xuser changes mode again),
- Xor "DIGEST" (digests are periodically sent), followed by a string that
- Xplays the role of the user's password, followed by either "YES" or "NO"
- Xwhich are the values of the conceal attribute, followed by the subscriber's
- Xname. See also \fIlistproc\fP(1).
- X.SH .RESTRICTED
- XThe format is as follows:
- X.PP
- XOne entry per line; each entry is the full email address of the
- Xsubscriber, followed by a file name where email addresses of recipients
- Xare listed (just like in the ".subscribers" file). Example:
- X.sp
- X.ce
- Xjdoe@foo.bar.com HOMEDIR/lists/LIST_ALIAS/.recipients
- X.sp
- XIf the recipient file given is the word "NONE", then no one will receive
- Xany messages.
- X.SH .ALIASES
- XIt is possible that a subscriber's/peer's/news group's/gateway's email
- Xmay arrive using a different path than registered, which may raise
- Xsubscription issues. To work around this,
- Xeach list provides a ".aliases" file in its subdirectory, which may contain
- Xalternate email addresses to be used when checking for subscription. The
- Xformat is one line per alias with the following information:
- X.sp
- X.ce
- Xalias-address address-as-subscribed
- X.sp
- XPlease note that only the subscribed address is used for sending out
- Xemail (see next section about regular expressions).
- X.PP
- XThe aliased address may be a regular expression with egrep(1) style syntax,
- Xin which case
- Xthe following characters have special meanings: '~', if leading the
- Xregular expression it reverses its meaning; '|' and '&' separate multiple
- Xregular expressions (logical OR and AND); '<' '>' group regular expressions
- X(we preserve the meaning of the parentheses from ed(1), and remove the
- Xmeaning of < and > from ed(1) since in the ListProcessor context they are either
- Xthe default, or inappropriate).
- XThese can be used literally by escaping them
- Xwith '\\'. In addition, the following characters should be defined
- Xin matched pairs: (), <>, [], "". For example:
- X.sp
- X.ce
- Xjdoe@.*\\.bar\\.com jdoe@foo.bar.com
- X.sp
- Xwill enable this user to send messages from any machine in his local
- Xnetwork and receive replies at foo.bar.com -- keep in mind that a '.'
- Xmatches exactly one character, and '.*' matches zero or more characters.
- XIn a more complicated example:
- X.sp
- X.ce
- X~jdoe@cc.*|jdoe@....*\\.bar\\.com jdoe@foo.bar.com
- X.sp
- Xwill match if jdoe sends a message from a machine whose name does not start
- Xwith 'cc', or from a machine whose name has at least 3 characters.
- X.PP
- XIf certain parts of the regular expression are parenthesized, then the
- Xstrings that matched the subexpressions can be used in
- Xthe 'address-as-subscribed' to form new return addresses; these matched
- Xstrings are accessed by \fI\\n\fP where \fIn\fP is a digit between 1 and
- X9. For example, if the sender is:
- X.sp
- X.ce
- XGATE!HOP!USER@UUCP.SOME.COM
- X.sp
- Xand the entry in the ".aliases" file reads:
- X.sp
- X.ce
- X[^!@]*!([^!@.]*)!([^!@]*)@.* \\2@\\1.UUCP
- X.sp
- Xthen what will be returned as 'address-as-subscribed' is:
- X.sp
- X.ce
- XUSER@HOP.UUCP
- X.sp
- XThis way you can map addresses coming in via various gateways to steady ones
- X(\\2 refers to the second set of parentheses, and \\1 to the first).
- XManagers may edit HOMEDIR/src/regex.c to test regular expression
- Xbehavior, introduce ls(1) style meanings to the * and ? wild characters,
- Xundefine ed(1) special characters, and enforce strict egrep(1) syntax (remove
- Xthe meanings of ~ & < and >).
- X.PP
- XRegular expressions should be used with caution for obvious reasons.
- X.PP
- XIf someone is experiencing subscription
- Xproblems, you may wish to add their alternate email address(es) in this
- Xfile. This includes regular subscribers, news groups, peers and gateways.
- XIf the sender is also a restricted subscriber, do not forget to put
- Xanother entry in ".restricted" with the new alternate address. Any
- Xnumber of aliases may be defined for each individual address.
- X.PP
- XIn addition, a ".aliases" file is also provided for ListProcessor
- Xrequests and is under HOMEDIR. The same syntax is used, but each
- Xentry has a slightly different meaning:
- X.sp
- X.ce
- Xaddress-as-arrived address-used-for-reply
- X.sp
- XIn this case, \fIaddress-used-for-reply\fP will be used to reply to all
- Xrequests sent in by \fIaddress-as-arrived\fP. A user may have any
- Xnumber of aliases, but only the first one matching
- X\fIaddress-as-arrived\fP will be used. Like before, the first argument may
- Xbe a regular expression and the second may use the matches in the first.
- X.sp
- XFor each new list, the system puts the following default alias in its
- X".aliases" file:
- X.sp
- X.ce
- X^@.*:(.*)@(.*\\..*) \\1@\\2
- X.sp
- XThis removes source routing.
- X.SH .IGNORED
- XAs described before, the system's home directory as well as every list's
- Xsubdirectory contains a ".ignored" file which is used to filter out messages
- Xsent by certain users. The default file contains entries for server,
- Xbin, and sys; you may wish to add an entry for every list alias that is
- Xdefined on your system. A list's ".ignored" file also contains an
- Xentry of its alias and full email address, as well as the server account's
- Xfull email address.
- X.PP
- XEntries in this file may also be regular expressions as explained in the
- Xprevious section. For example, to restrict requests (and postings)
- Xto .com and .edu domain addresses, one may add:
- X.sp
- X.ce
- X~<.*\\.com|.*\\.edu>
- X.sp
- XNotice, it is incorrect to list them as follows:
- X.sp
- X.ce
- X~.*\\.com
- X.ce
- X~.*\\.edu
- X.sp
- Xas anything not from the .com domain matches the first regular expression,
- Xand therefore will be ignored.
- XTo refuse access to certain user names and certain sites one may include:
- X.sp
- X.ce
- X \.*\\.bar\\.com|jdoe@.*
- X.sp
- XThe system's manager should use extra caution when adding regular expressions
- Xto the system's ".ignored" file, because a simple '.*' prohibits anyone from
- Xusing its services.
- X.SH SEE\ ALSO
- Xcatmail(1), listproc(1), server(1), serverd(1), start(1)
- X.SH AUTHOR
- X.nf
- XAnastasios C. Kotsikonas
- XCopyright (c) 1991-93, Anastasios Kotsikonas
- XComments to tasos@cs.bu.edu
- X.fi
- *-*-END-of-doc/list.1-*-*
- echo x - doc/listproc.1
- sed 's/^X//' >doc/listproc.1 <<'*-*-END-of-doc/listproc.1-*-*'
- X.\" ListProcessor System
- X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
- X.\"
- X.TH listproc 1 "ListProcessor"
- X.SH NAME
- X\fBlistproc\fP \- process requests sent to the ListProcessor request handler
- X.SH SYNOPSIS
- X\fBlistproc\fP [\fB-1\fP] [\fB-e\fP] [\fB-i\fP] [\fB-n\fP] {[\fB-a\fP\ <\fBLIST_ALIAS\fP>]}* {[\fB-r\fP\ <\fBreq\fP>]}* {[\fB-d\fP\ <\fBreq\fP>]}* {[\fB-b\fP\ <\fBreq\fP>]}* [\fB-B\fP] [\fB-D\fP]
- X.SH DESCRIPTION
- X\fIlistproc\fP processes user requests sent to \fIlistproc@your-domain\fP,
- Xforwards requests about known remote lists, and processes list-owner
- Xadministrative requests (see also the LIST\ OWNERS section below).
- XEach request should appear in a separate line with any possible arguments.
- XThe file
- X".ignored" is used in the system's home directory to filter out unwanted
- Xsenders. If the system is not instructed to ignore invalid requests
- X(see the CONFIG section in \fIserver(1)\fP), the sender is notified of the first
- Xinvalid request; all subsequent requests are ignored.
- XFor each successfully completed request,
- Xa confirmation is sent back to the sender.
- X.PP
- X\fIlistproc\fP stops reading
- Xrequests when it encounters the string "--" in a line by itself, which
- Xon most systems signifies the start of the .signature message, or at the
- Xfirst occurence of a thankful request. \fIlistproc\fP reads the \fIconfig\fP
- Xfile (see \fIserver(1)\fP).
- X.PP
- XSubscriptions may be
- Xmanager-approved (private lists), files and archive indices may be password
- Xprotected (private archives), and requests may be placed in a batch queue.
- XA single request may span multiple lines if each part ends with
- X\fI&\\n\fP.
- X.SH USER\ REQUESTS
- XThe following user requests are recognized (requests may be abbreviated):
- X.TP
- X\fIhelp\fP\ [topic]
- XSend a help message on all valid requests or the selected topic (possibly
- Xa request) only.
- X.TP
- X\fIset\fP\ list\ [option arg(s)]
- XWithout the optional arguments, return the current values for all options
- Xset for \fIlist\fP; otherwise,
- Xset subscriber preferences for \fIlist\fP.
- X.sp
- X\fIoption\fP can be:
- X.in +2
- X.sp
- X\fImail\fP: set mail preferences.
- X.sp
- X.in +2
- X\fIarg\fP has to be one of the following:
- X.sp
- X.in +2
- X\fIack\fP: send a copy of the current message to the original sender.
- X.sp
- X\fInoack\fP: do not send a copy of the current message to the original sender.
- XThis is the default for newly subscribed users.
- X.sp
- X\fIpostpone\fP: do not send any messages to the particular subscriber until
- Xhe changes status again.
- X.sp
- X\fIdigest\fP: do not send individual messages to the particular
- Xsubscriber. Instead, store messages in a digest and send it when the
- Xdigest exceeds a specified number of lines, or when a specified amount
- Xof time has passed since the last digest was sent.
- X.sp
- XIf the mail mode is changed from \fIdigest\fP to anything else,
- Xall messages currently stored for the next digest will be sent to the
- Xsubscriber at once, in digest format.
- X.in -2
- X.in -2
- X.sp
- X\fIpassword\fP: change the password (used to establish
- Xsubscriber privileges when connecting to ListProcessor for a "live" session and
- Xfor the option below).
- X.sp
- X.in +2
- X\fIargs\fP must be: old-password new-password.
- X.in -2
- X.sp
- X\fIaddress\fP: set the address the user is subscribed with (if allowed for this
- Xlist).
- X.sp
- X.in +2
- X\fIargs\fP must be: current-password new-address.
- X.sp
- X.in -2
- X\fIconceal\fP: set the user's visibility.
- X.sp
- X.in +2
- X\fIarg\fP must be one of the following:
- X.sp
- X.in +2
- X\fIyes\fP: the user is not listed in \fIrecipients\fP and \fIstatistics\fP
- Xrequests.
- X.sp
- X\fIno\fP: the user's email address and name are made public.
- X.in -2
- X.in -2
- X.in -2
- X.TP
- X\fIsubscribe\fP\ list\ full_name
- XSubscribe the sender to \fIlist\fP (note, his email address is used for
- Xsubscription, not his \fIfull_name\fP). A password is assigned by the
- Xsystem at that time and is included in the reply message to the new
- Xsubscriber. The password is to be used when connecting to the interactive
- Xpart of the system for identification purposes, and for changing the
- Xsubscription address if allowed for this list.
- X.TP
- X\fIwhich\fP
- XGet a list of local mailing lists to which the sender has subscribed.
- X.TP
- X\fIunsubscribe\fP\ list
- XRemove the sender from the specified \fIlist\fP.
- X.TP
- X\fIsignoff\fP\ list
- XAlias of the unsubscribe request.
- X.TP
- X\fIrecipients\fP\ list
- XGet a list of all subscribers of \fIlist\fP. The request is also forwarded
- Xto all peer lists, and the servers handling them will respond accordingly.
- XThe user is notified when this request is being forwarded. If a list
- Xis private, only members may issue this request.
- X.TP
- X\fIreview\fP\ list
- XAlias of the recipients request.
- X.TP
- X\fIinformation\fP\ list
- XGet information about a particular \fIlist\fP.
- X.TP
- X\fIstatistics\fP\ list\ {[subscriber\ email\ address(es)]\ |\ [-all]}
- XObtain a count of messages sent per subscriber to the specified \fIlist\fP,
- Xor by those subscribers given as argument only (wild characters are
- Xsupported). If \fI-all\fP is specified, then statistics are compiled for all
- Xusers (currently subscribed or not) who have posted to the list in the past.
- XThe request is also forwarded to all peer lists and the
- Xservers handling them will respond accordingly.
- XThe user is notified when this request is being forwarded.
- XIf a list is private, only members may issue this request.
- X.TP
- X\fIrun\fP\ list\ [password\ cmd\ [args]]
- XWithout the optional arguments, just list all commands that may be executed
- Xby subscribers of this \fIlist\fP. Otherwise, run \fIcmd\fP with the
- Xoptional \fIargs\fP, if the correct \fIpassword\fP is provided. The reply
- Xwill contain the output from stdout and/or stderr.
- X.TP
- X\fIlists\fP
- XObtain a list of mailing list addresses that are serviced by this system,
- Xwith a small description of their purpose. If remote lists (see below)
- Xare also defined, their addresses and descriptive messages will also be
- Xincluded.
- X.TP
- X\fIindex\fP\ [archive\ |\ path-to-archive]\ [/password]\ [-all]
- XObtain an index of files in the specified \fIarchive\fP (or the master archive
- Xif none specified) and all of its subarchives if the the \fI-all\fP
- Xoption is specified. Certain archives may be
- Xprivate, and these require a \fI/password\fP to be able to obtain their
- Xindices. Archives on different places in the hierarchy may have the same
- Xnames and they can be distinguished by specifying paths to them;
- X\fIpath-to-archive\fP has the form \fIarchive[/archive[/archive...]]\fP.
- X\fIindex\fP requests always report the paths to the archives they list.
- X.TP
- X\fIget\fP\ <archive\ |\ path-to-archive>\ file\ [/password]\ [parts]
- XGet the specified \fIfile\fP from the \fIarchive\fP given. The file
- Xmay have been
- Xsplit into smaller parts due to its size, in which case each part will
- Xbe sent in a different email message. If only certain \fIparts\fP are desired,
- Xthey may be given as arguments (numbers, separated by spaces -- ranges
- Xare not recognized). Certain archives may be private, in which case their
- X\fI/password\fP has to be provided in order to get the desired files.
- XArchives on different places in the hierarchy may have the same
- Xnames and they can be distinguished by specifying paths to them;
- X\fIpath-to-archive\fP has the form \fIarchive[/archive[/archive...]]\fP.
- XIf the file is pure binary, it will be uuencoded first.
- X.TP
- X\fIsearch\fP\ <archive\ |\ path-to-archive>\ [/password]\ [-all]\ <pattern>
- XSearch all files in the specified archive (and all of its subarchives if
- X\fI-all\fP) and return lines that match the \fIpattern\fP.
- XThe pattern can be an extended regular expression with egrep(1)-style syntax,
- Xwith support for the following additional operators: '~', if leading the
- Xregular expression it reverses its meaning; '|' and '&' separate multiple
- Xregular expressions (logical OR and AND); '<' '>' group regular expressions
- X(we preserve the meaning of the parentheses from ed(1), and remove the
- Xmeaning of < and > from ed(1) since in the ListProcessor context they are either
- Xthe default, or inappropriate).
- XThese can be used literally by escaping them
- Xwith '\\'. In addition, the following characters should be defined
- Xin matched pairs: (), <>, []. \fIpattern\fP may be enclosed in single
- Xor double quotes. Pattern matching is case insensitive.
- X.TP
- X\fIfax\fP\ <fax-no>\ <archive\ |\ path-to-archive>\ file\ [/password]\ [parts]
- XSame as the \fIget\fP request except that the files are faxed to the
- Xspecified number.
- X.TP
- X\fIrelease\fP
- XGet information about the current release of this server system.
- X.TP
- X\fIexecute\fP\ password\ #command\ [arguments]
- XIntended for the system's \fImanager\fP, this will execute the \fIcommand\fP
- Xwith the optional \fIarguments\fP and send the output (if any) from stdout
- Xand/or stderr to the sender. See the sample \fIconfig\fP file for
- X\fIpassword\fP definition.
- X.PP
- XFor a list of the list administration requests that may be issued by list
- Xowners, see the LIST\ OWNERS section below.
- X.SH OPTIONS
- XThe following command line options are recognized:
- X.TP
- X-1
- XExecute only once; process any requests and return control to
- X\fIserverd\fP(1); any new messages that may have arrived in the meantime will
- Xbe processed at a later time. Without this option, \fIlistproc\fP will be
- Xlistening for requests for ever. \fIserverd\fP(1)
- Xuses this option by default when spawning \fIlisterv\fP.
- X.TP
- X-e
- XEcho reports to the screen; it has no effect if the system has been compiled
- Xwith -DSYSLOG.
- X.TP
- X-i
- XGo to interactive mode -- messages by \fIlistproc\fP are not mailed out
- Xbut instead \fIserverd\fP(1) reads them during its interactive session. Do not
- Xuse this option in the \fIconfig\fP file (see \fIserver(1)\fP).
- X.TP
- X-n
- XBy default, peer servers are notified upon \fIstatistics\fP and
- X\fIrecipients\fP requests. The system uses a protocol for avoiding
- Xloops as described in \fIserver\fP(1).
- XIf you detect loops with other servers, you should use this option to
- Xturn off notification of peer servers.
- X.TP
- X-a LIST_ALIAS
- XUsually, subscriptions are automatic. This option turns off automatic
- Xsubscription to the specified list (\fILIST_ALIAS\fP should be in capital
- Xletters), and makes this list private (members only may issue \fIrecipients\fP
- Xand \fIstatistics\fP requests). The sender is notified of this effect,
- Xand a message is sent
- Xto the list's owner requesting his/her approval, with instructions for
- Xplacing the subscription. Notice that the specified list has to be defined
- Xbeforehand via a \fIlist\fP directive in the \fIconfig\fP file. This
- Xoption may be repeated any number of times.
- X.TP
- X-c LIST_ALIAS
- XConceal \fILIST_ALIAS\fP from \fIlists\fP requests.
- X.TP
- X-r request
- XPlace a restriction on the specified server \fIrequest\fP as outlined above.
- XIf the number of users on the system at the time the request is about
- Xto be processed is above the limit
- Xgiven in the \fIconfig\fP file (using the \fIrestriction\fP directive),
- Xthe request is rejected \-\- meant for requests that may take a
- Xconsiderable amount
- Xof resources such as the \fIstatistics\fP request \-\- this option may
- Xbe repeated any number of times. List administration requests are not
- Xsubject to these restrictions (see later on).
- X.TP
- X-d request
- XDisable \fIrequest\fP, i.e. make it totally unknown to the server \-\- this
- Xsupersedes any \fIdisable\fP directives for this request in the \fIconfig\fP
- Xfile, i.e. this request will not be recognized for any list (see
- X\fIserver\fP(1)).
- XHowever, help is still available for that request. List administration
- Xrequests are also subject to these restrictions (see later on). This
- Xoption may be repeated any number of times.
- X.TP
- X-b request
- XAll such \fIrequest\fPs will be batch-processed if they arrive between
- Xthe hours specified in the \fIconfig\fP file.
- XThis option may be repeated any number of times.
- X.TP
- X-B
- XProcess the batch queue. This is done automatically by \fIserverd\fP(1) after
- Xmidnight every day, or when the system is restarted, so no further action
- Xneeds to be taken. Caution:
- Xdo not place this option in the definition of \fIserver\fP in the
- X\fIconfig\fP file. If you do so, only the batch queue
- Xwill be processed (no new requests will be processed, ever).
- XThe batch queue is processed once a day only, unless the system
- Xis restarted repeatedly.
- X.TP
- X-D
- XTurns debugging on. When the \fIsystem\fP mailmethod is used, a
- Xcopy of the last SMTP transaction can be found in the files
- XHOMEDIR/sent and HOMEDIR/received.
- X.SH PEER\ SERVERS
- XThe system supports the notion of remote lists. A ListProcessor may know of
- Xremote lists served by remote servers. Yet users may send requests about
- Xthese remote lists to this server, which will in turn forward
- Xthem to the remote servers. The user is notified when a list is not local
- Xand his/her request is about to be forwarded.
- XA \fIlists\fP request will tell the user which remote lists are known
- Xto this server.
- X.PP
- XRemote lists should be made known
- Xto this server only if they are served by a server of version 5.31 or higher.
- XThis restriction is posed because of incompatible requests
- Xacross various list management systems. See the
- Xdiscussion about the \fIconfig\fP file for setting up remote lists.
- X.PP
- XIn addition, \fIrecipients\fP and \fIstatistics\fP requests are
- Xforwarded to the servers handling peer lists (the -n flag to \fIlistproc\fP
- Xturns this feature off).
- X.SH LIST\ OWNERS
- XList owners are individuals responsible for list administration via
- Xmail requests. Thus, list owners may be remotely located. Each list
- Xhas to have at least one list owner. These owners may be different than
- Xthe system's \fImanager\fP, and have special privileges: they may issue
- Xrequests on users' behalf (add a user, remove a user, etc.) overriding
- Xsystem restrictions set on regular users (these include disabled commands
- Xas described above),
- Xobtain reports about the lists they administer,
- Xappend to the ".aliases" and ".ignored" files, change the welcoming
- X(".welcome") and informative (".info") messages, as well as other system
- Xfiles such as the aliases file (".aliases"), the ".ignored" file, the
- Xsubscribers file (".subscribers"), the news file (".news") and the
- Xpeers file (".peers"). In addition, they may moderate their lists and they
- Xreceive various error messages pertaining to their lists.
- XAll administrative requests are author authenticated and
- Xpassword protected. Whenever a message cannot be author authenticated,
- Xthe list's owner and \fImanager\fP are notified.
- X.PP
- XOn the other hand, list owners may not add restricted users; this
- Xservice can be provided by contacting the system's \fImanager\fP.
- X.PP
- XList owners may also receive copies of user requests and/or error
- Xmessages such as invalid postings, syntax errors on requests, etc.
- XThese options are described in the following sections.
- X.TP
- XDefining list owners
- XOnce a new mailing list is defined in the \fIconfig\fP file, the list's
- Xowner address and access password are provided to the \fIlist\fP directive.
- XOf course, this password should be made known to the owner; it
- Xwill be needed for all administrative requests. Next, the owner's
- Xaddress has to be registered in HOMEDIR/owners; the \fImanager\fP
- Xsimply edits this file adding the owner's address along with the
- Xlist's name (alias) he is assigned to, followed by any
- Xpreferences (see below).
- XMultiple owners for a list may be defined by adding their addresses to
- Xthis file, and providing them with the list's password. However, only
- Xthe primary owner's address (as defined by the \fIlist\fP directive) will
- Xbe used as reference in correspondence and for system-error notifications,
- Xand only the primary owner will be forwarded messages from his moderated list
- Xfor approval.
- XThe \fImanager\fP should also add his address (login name) to this file.
- X.TP
- XOwner preferences
- XThe primary owner may wish to be copied on certain replies to user
- Xrequests (such as subscribe), on error conditions (rejected
- Xpostings, invalid requests, etc.), or on all cases. These preferences
- Xare listed in the \fIowners\fP file on the line his address and list are
- Xdefined. Valid preferences are:
- X.sp
- X.in +2
- XCCSET: copy on \fIset\fP requests.
- X.sp
- XCCSUBSCRIBE: copy on \fIsubscribe\fP requests.
- X.sp
- XCCUNSUBSCRIBE: copy on \fIunsubscribe\fP requests.
- X.sp
- XCCRECIPIENTS: copy on \fIrecipients\fP requests.
- X.sp
- XCCINFORMATION: copy on \fIinformation\fP requests.
- X.sp
- XCCSTATISTICS: copy on \fIstatistics\fP requests.
- X.sp
- XCCRUN: copy on \fIrun\fP requests.
- X.sp
- XCCPRIVATE: copy on requests rejected because they are open only to
- Xthe list's members.
- X.sp
- XCCERRORS: copy on various error conditions.
- X.sp
- XCCALL: all of the above.
- X.in -2
- X.sp
- XOwner preferences are optional.
- X.PP
- XThe \fImanager\fP may define preferences
- Xfor himself as well by using the keyword \fIserver\fP in place of a
- Xlist alias. However, such preferences make sense only in the following
- Xcases:
- X.sp
- X.in +2
- XCCGET: copy on \fIget\fP requests.
- X.sp
- XCCINDEX: copy on \fIindex\fP requests.
- X.sp
- XCCLISTS: copy on \fIlists\fP requests.
- X.sp
- XCCRELEASE: copy on \fIrelease\fP requests.
- X.sp
- XCCHELP: copy on \fIhelp\fP requests.
- X.sp
- XCCERRORS: copy on various error conditions.
- X.sp
- XCCALL: all of the above.
- X.in -2
- X.sp
- XManager preferences are optional.
- X.TP
- XOwner privileges
- XWhenever an owner issues a user request on a user's behalf (see below),
- Xall restrictions, including disabled commands, do not apply. All other
- Xadministrative requests are subject to restrictions set by the \fImanager\fP.
- XAll requests (user and administrative) are subject to batch-processing.
- X.TP
- XAdministrative requests
- XThe following requests may be issued by a list's owner:
- X.TP
- X\fIsystem\fP\ list password\ user-address\ #user-request
- XThis request overrides all system restrictions and executes
- X\fIuser-request\fP on behalf of \fIuser-address\fP; this
- Xaddress has to appear as listed in the ".subscribers" file, where applicable.
- XThe most frequent use of the \fIsystem\fP request is to subscribe a user
- Xto a private list. For example:
- X.sp
- X.in +2
- Xsystem herc herc1 john@foo #subscribe herc Some Name
- X.in -2
- X.sp
- XIf a \fIuser-request\fP refers to a list, this list has to be
- X\fIlist\fP, so that a list's owner may not have privileges over another
- Xlist's affairs. Note that all replies about \fIuser-request\fP are
- Xforwarded to \fIuser-address\fP, not the owner; therefore, care has to
- Xbe taken to avoid syntax errors. The \fIsystem\fP request is not subject
- Xto restrictions, disabled requests, and private list subscription
- Xverification (it is still subject to private list review as outlined
- Xabove, and batching). To remove a member from his list, the owner may issue the
- Xfollowing request:
- X.sp
- X.in +2
- Xsystem herc herc1 john@foo #unsubscribe herc
- X.in -2
- X.sp
- XTo bypass restrictions and review his list, the owner may issue the
- Xfollowing:
- X.sp
- X.in +2
- Xsystem venus venus1 his-address #review venus
- X.in -2
- X.sp
- XIn general, \fIuser-request\fP may be any of the recognized user requests
- Xdescribed under \fIlistproc\fP. The pound sign is mandatory.
- XThere is no help available to users for this request for security reasons.
- X.TP
- X\fIapprove\fP\ list\ password\ tag
- XWhenever a new message arrives for a moderated list a copy is sent to the
- Xlist's owner soliciting his approval -- proper instructions for approving
- Xor discarding a message are included. This request
- Xapproves the message identified by the \fItag\fP number for posting to
- X\fIlist\fP. The tag number is
- Xprovided to the list's owner by \fIlistproc\fP and is unique.
- X.TP
- X\fIdiscard\fP\ list\ password\ tag
- XIn contrast to the above request, this discards the message identified
- Xby \fItag\fP. Messages that are not approved or discarded remain in the
- Xlist's \fImoderated\fP file (see \fIlist\fP(1)).
- X.TP
- X\fIreports\fP\ list\ password
- XObtain all reports pertinent to \fIlist\fP; this will send two mail messages:
- Xone with the current report (HOMEDIR/lists/ALIAS/.report.list), and
- Xone with the previously archived ones (HOMEDIR/lists/ALIAS/.rep.list.acc);
- Xsee the REPORTS section below. Once the ".rep.list.acc" file is sent,
- Xit is shrunk in size, therefore the owner should make sure he keeps the
- Xcopy he receives.
- X.sp
- XThis request has no effect if the system is using syslog(3) to generate
- Xreports.
- X.TP
- X\fIedit\fP\ list\ password\ file
- XObtain the specified \fIfile\fP for editing; candidate files are:
- X.sp
- X.in +2
- X\fIaliases\fP: obtain the list's aliases file.
- X.sp
- X\fIignored\fP: obtain the list's list of unwelcome addresses.
- X.sp
- X\fIinfo\fP: obtain the list's informative message.
- X.sp
- X\fIsubscribers\fP: obtain the list's subscribers list.
- X.sp
- X\fIwelcome\fP: obtain the list's welcoming message.
- X.sp
- X\fInews\fP: obtain the list's list of newsgroup connections.
- X.sp
- X\fIpeers\fP: obtain the list's peers.
- X.in -2
- X.TP
- X\fIput\fP\ list\ password\ keyword\ [args]
- XThis enables the list's owner to append to the ".aliases" and ".ignored" files,
- Xand replace his list's ".welcome", ".info", ".aliases", ".ignored",
- X".subscribers", ".news" and ".peers" files, depending
- Xon the \fIkeyword\fP. Valid \fIkeyword\fPs are:
- X.in +2
- X.sp
- X\fIalias\fP: Add a user address alias to the list's and system's ".aliases"
- Xfiles (see .ALIASES below). This requires the new address and the address
- Xused for subscription as arguments:
- X.sp
- Xput <list> <password> alias <new-alias> <address-as-subscribed>
- X.sp
- XFor example:
- X.sp
- X.in +2
- Xput venus venus1 alias foo!john john@foo
- X.in -2
- X.sp
- X\fIignore\fP: Add a user address to the list's ".ignore" file only. Of
- Xcourse this address has to be provided as argument:
- X.sp
- Xput <list> <password> ignore <address-as-subscribed-or-aliased>
- X.sp
- XFor example:
- X.sp
- X.in +2
- X.nf
- Xput ermis ermis1 ignore jack@foo
- Xput ermis ermis1 ignore foo!jack
- X.fi
- X.in -2
- X.sp
- X.nf
- X\fIwelcome\fP,
- X\fIinfo\fP,
- X\fIaliases\fP,
- X\fIignored\fP,
- X\fIsubscribers\fP,
- X\fInews\fP,
- X.fi
- X\fIpeers\fP: Create a new system file.
- X.sp
- XFor example:
- X.sp
- X.in +2
- X.nf
- Xput <list> <password> subscribers
- Xtasos ACK PASSWORD NO Tasos Kotsikonas
- Xjohn NOACK PASS1 NO John Doe
- X.fi
- X.in -2
- X.sp
- XNo arguments are needed. The text that is to
- Xgo to the corresponding file starts at the line following this request
- Xand spans till the end of the mail message. Thus, no more requests can
- Xbe made in the same mail message -- they are treated as regular text;
- Xsignature lines also signify the end of text, provided they start with
- X"--" in a single line.
- X.in -2
- X.sp
- XA confirmation is sent to the owner once a \fIput\fP request is successfully
- Xprocessed.
- X.SH OWNERS
- XThe format of the \fIowners\fP file is as follows:
- X.sp
- XOne entry per line; each entry is the full email address of a list's
- Xowner, followed by the list alias he owns, followed by any optional
- Xpreferences. If the keyword \fIserver\fP is specified in place of the
- Xlist alias, then preferences are defined for the \fImanager\fP.
- X.SH SEE\ ALSO
- Xcatmail(1), farch(1), list(1), queue(1), server(1), serverd(1), start(1)
- X.SH AUTHOR
- X.nf
- XAnastasios C. Kotsikonas
- XCopyright (c) 1991-93, Anastasios Kotsikonas
- XComments to tasos@cs.bu.edu
- X.fi
- *-*-END-of-doc/listproc.1-*-*
- echo x - doc/queue.1
- sed 's/^X//' >doc/queue.1 <<'*-*-END-of-doc/queue.1-*-*'
- X.\" ListProcessor System
- X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
- X.\"
- X.TH queue 1 "ListProcessor"
- X.SH NAME
- X\fBqueued\fP \- ListProcessor mail queue daemon
- X.SH SYNOPSIS
- X\fBqueued\fP <\fBfrequency\fP>
- X.SH NAME
- X\fBpqueue\fP \- process the specified mail queue files
- X.SH SYNOPSIS
- X\fBpqueue\fP [\fB-e\fP] [\fB-D\fP] <\fBfiles\fP>
- X.SH OVERVIEW
- XThis part of the ListProcessor system can be employed only when using the
- X\fIsystem\fP mailmethod (see \fIserver\fP(1)).
- XMessages and replies to requests not
- Xdelivered due to network problems are queued by the system in the
- Xdirectory HOMEDIR/mqueue. This part of the system attempts periodic
- Xredelivery of these files. If problems still persist, files (messages)
- Xthat cannot be delivered are requeued.
- X.SH DESCRIPTION:\ queued
- XThis is the daemon that looks for files in the mail queue. It uses
- X\fIpqueue\fP for redelivery. The queue is checked every \fIfrequency\fP
- Xseconds. Whenever an error occurs with \fIpqueue\fP, \fIqueued\fP sends
- Xa mail message to \fImanager\fP (as defined in the \fIconfig\fP file)
- Xand aborts.
- X.PP
- X\fIqueued\fP is not spawned by \fIstart\fP(1) in order to reduce the number of
- Xprocesses running, since the probability of messages being queued is
- Xvery low. Instead, it should be started manually whenever there are
- Xfiles in the mail queue directory.
- X.SH DESCRIPTION:\ pqueue
- XThe \fIfiles\fP given as arguments are redelivered. If any of these
- Xcannot be redelivered, they are requeued and will be processed in the next
- Xrun. \fIpqueue\fP reports to the file HOMEDIR/.report.pqueue
- X.PP
- XThe following command line options are recognized:
- X.TP
- X-e
- XEcho reports to the screen; it has no effect if the system has been compiled
- Xwith -DSYSLOG.
- X.TP
- X-D
- XTurns debugging on; a copy of the last SMTP transaction can be found in
- Xthe files HOMEDIR/sent and HOMEDIR/received. Warning: these files
- Xare also used by \fIlist\fP(1) and \fIlistproc\fP(1) when they have their
- Xdebug mode on, so use caution.
- X.SH NOTE
- XThis mail queueing system should not be confused with the one implemented
- Xby sendmail(1).
- X.SH SEE\ ALSO
- Xserver(1)
- X.SH AUTHOR
- X.nf
- XAnastasios C. Kotsikonas
- XCopyright (c) 1991-93, Anastasios Kotsikonas
- XComments to tasos@cs.bu.edu
- X.fi
- *-*-END-of-doc/queue.1-*-*
- echo x - doc/server.1
- sed 's/^X//' >doc/server.1 <<'*-*-END-of-doc/server.1-*-*'
- X.\" ListProcessor System
- X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
- X.\"
- X.TH server 1 "ListProcessor"
- X.SH NAME
- XListProcessor version 6.0
- X.SH OVERVIEW
- XThis is a system that implements various mailing lists with one
- Xlist manager. It is automated, and obliterates the need for user intervention
- Xand maintenance of multiple aliases of the form "list, list-owner,
- Xlist-request", etc. There is support provided for public and private
- Xhierarchical archives,
- Xmoderated and non-moderated lists, peer lists, peer servers, private
- Xlists, address aliasing, news connections and gateways, mail queueing,
- Xdigests, list ownership, owner preferences, crash recovery, batch
- Xprocessing, configurable headers, regular expressions, archive searching,
- Xand live user connections via TCP/IP.
- X.SH OBTAINING\ INFORMATION
- X.TP
- Xmailing lists, aliases, news groups, peer lists
- XSee list(1).
- X.TP
- Xuser requests, list owners, peer servers, remote lists
- XSee listproc(1).
- X.TP
- Xdistributing incoming mail
- XSee catmail(1).
- X.TP
- Xarchiving files
- XSee farch(1).
- X.TP
- Xarchiving of lists' messages
- XSee below.
- X.TP
- Xprocessing the mail queue
- XSee queue(1).
- X.TP
- Xoptions for the system's daemon
- XSee serverd(1).
- X.TP
- Xstarting and stopping the system
- XSee start(1).
- X.TP
- Xlive connections
- XSee ilp(1) and serverd(1).
- X.SH SYSTEM\ SETUP
- XThe ListProcessor system is installed under the HOMEDIR directory as defined
- Xin src/Makefile; HOMEDIR points to the top level directory of the installation;
- Xa \fIserver\fP user account has to be setup. The system should be installed and
- Xset up using this account, and always be started from this account as well
- X(see \fIstart\fP(1)).
- XThen, the following alias
- Xhas to be defined in /etc/aliases, /usr/lib/aliases or /usr/ucblib/aliases
- X(depending
- Xon your system) for listprocessor (where users send their requests):
- X.sp
- X.in +2
- Xlistproc: "|HOMEDIR/catmail -r -f"
- X.in -2
- X.PP
- XVarious mailing lists are set up in a similar fashion; see \fIlist\fP(1).
- X.PP
- XIt is important to keep in mind that mailers should convert any text lines
- X(not header lines) of incoming messages starting with "From ", to ">From ".
- XThis is automatically done by the -f flag to \fIcatmail\fP(1).
- X.PP
- XThe \fIcatmail\fP(1) utility is used to append incoming mail to the appropriate
- Xfiles. When properly set up, it has the setuid bit turned on. Since
- Xexecute permission is granted to everybody, it is possible for anyone
- Xto append to these files; however, each time \fIcatmail\fP(1) is run, it
- Xreports the user id and user name whom access was granted to.
- X.PP
- XIf the system is to go interactive (see \fIserverd\fP(1)), you have to add
- Xthe following line in your /etc/services file:
- X.sp
- X.ce
- Xulistproc 372/tcp
- X.sp
- XSee also src/Makefile.
- X.PP
- XHow the system operates is defined in the \fIconfig\fP file (see below).
- XOnce the system is loaded, you will have to run the script \fIsetup\fP;
- Xthis will ensure that all necessary files and directories are present, and
- Xhave the right permissions. Before starting the
- Xsystem, you may wish to edit the ".ignored" file in HOMEDIR (see \fIlist\fP(1)).
- XAt this point, you may also wish to alter the help files in HOMEDIR/help;
- Xeach file in that directory corresponds to one of the recognized requests.
- XHelp files may be simple text files, or shell scripts starting with "#!"
- Xin the first line, followed by the shell to execute.
- X.PP
- XFile protections are a major issue and the requirements may vary from system
- Xto system. The problems usually arise from inadequate write permissions while
- Xappending mail to the various mail files. The system uses the environment
- Xvariable ULISTPROC_UMASK in the same way as umask(1) is used when updating
- Xfiles. If not set, the default is 066. A value of 026 should be acceptable in
- Xmost cases. This variable should be set in both .cshrc and .profile. For
- Xarchived files, you may use the ULISTPROC_ARCHIVES_UMASK variable, which
- Xdefaults to the value set for ULISTPROC_UMASK.
- X.PP
- XFinally, experiment with the various mail methods described below, until
- Xyou get the proper "From " line in the beginning of the outgoing message;
- Xfor instance, when \fIlistproc\fP(1) is replying to a request, you should see
- Xsomething like "From listproc@your-domain" as the first line of the header;
- Xor when
- Xthe list abc is distributing messages, this line should look like
- X"From abc@your-domain". If you cannot get it to work, i.e. you get something
- Xlike "From server@your-domain" then the server system may have
- Xto run with superuser privileges. In this case, the server userid should
- Xbe the same as root's. Also consult the PORT\ SPECIFIC section below,
- Xfor suggested mailmethods. You will not have any of these problems
- Xif you use the \fIsystem\fP mailmethod (see below).
- X.PP
- XIf this part of the setup is not done properly, peer lists will not
- Xwork at all and users may not be able to reply to the list. As a final
- Xnote, if \fItelnet\fP does not seem to be sending any mail, it is a
- Xbug with the telnet implementation on your system: telnet
- Xcannot have its input redirected or piped, and should be reported to your
- Xvendor.
- X.PP
- XThe last step for a complete set up is to define your system in the
- X\fIconfig\fP file.
- X.SH CONFIG
- XThe server system is defined in the \fIconfig\fP file; an example
- Xfile is provided with the system. This file is used by \fIstart\fP(1),
- X\fIserverd\fP(1), \fIlist\fP(1) and \fIlistproc\fP(1), and is not a shell
- Xscript.
- X.PP
- XThe following keywords (directives) are recognized and is advisable that each
- Xone of them starts at column 1; directives may span multiple lines if each
- Xline is terminated by &\\n:
- X.TP
- X\fIorganization\fP name
- XThis defines your organization when posting to news and upon connection
- Xestablishment of a live session. \fIname\fP may
- Xinclude blanks.
- X.TP
- X\fIserver\ listproc\fP@your-domain\ command-line-options
- XThis defines the list processor; the first argument is the full email address
- Xof the server (e.g. listproc@foo.edu) followed by any command line
- Xoptions to be used when \fIserverd\fP spawns \fIlistproc\fP
- X(see \fIserverd\fP(1), \fIlistproc\fP(1)).
- X.TP
- X\fIlist\fP\ list_alias\ email-addr\ owner-addr\ password\ cmd-line-opt
- XThis defines a mailing list; the first argument is the list's alias
- Xin /etc/aliases, /usr/lib/aliases or /usr/ucblib/aliases (see \fIlist\fP(1)),
- Xfollowed by its full email
- Xaddress, followed by its owner's full email address, followed by the
- Xlist's password for maintenance, followed by any command line options
- Xto be used when \fIserverd\fP(1) spawns \fIlist\fP(1).
- X.TP
- X\fIheader\fP\ list\ {\ [Header-Line:]\ ...\ }
- XIt specifies precious header lines from the original sender's message
- Xthat are to be preserved during distribution. The \fIlist\fP has to be
- Xdefined before, and precious header lines are specified within the
- Xenclosing \fI{\fP and \fI}\fP, possibly spanning multiple lines.
- X.TP
- X\fIdefault\fP\ list\ {\ [option = value]\ ...\ }
- XDetermine various default values for \fIlist\fP for new and current subscribers;
- Xthe list has to be defined before. Pairs of options and values may be repeated
- Xany number of times, and may span multiple lines; if certain options are
- Xmissing, then system defaults are used. Valid \fIoption\fPs are:
- X.sp
- X.in +2
- X\fIaddress\fP: turn user-settable subscription addresses on or off. Valid values
- Xare:
- X.sp
- X.in +2
- X\fIfixed\fP: users are not allowed to change the address they are subscribed
- Xwith via the \fIset <list> address\fP request (see \fIlistproc\fP(1)).
- XThis is the system default as well.
- X.sp
- X\fIvariable\fP: opposite of the above.
- X.in -2
- X.sp
- X\fImail\fP: select the default mail mode for new subscribers. Valid values are:
- X.sp
- X.in +2
- X\fIack\fP: see \fIset\fP in \fIlistproc\fP(1).
- X.sp
- X\fInoack\fP: see \fIset\fP in \fIlistproc\fP(1); this is the system default.
- X.sp
- X\fIpostpone\fP: see \fIset\fP in \fIlistproc\fP(1) (a rather useless setting indeed).
- X.sp
- X\fIdigest\fP: see \fIset\fP in \fIlistproc\fP(1).
- X.in -2
- X.sp
- X\fIpassword\fP: define a single password for new users; if missing, the system
- Xassigns a random password. Any string that contains no white spaces may be
- Xused.
- X.sp
- X\fIconceal\fP: determine the default visibility of new users; see \fIset\fP
- Xin \fIlistproc\fP(1). Valid options are:
- X.sp
- X.in +2
- X\fIyes\fP: hidden from \fIrecipients\fP and \fIstatistics\fP requests.
- X.sp
- X\fIno\fP: this is the system default.
- X.in -2
- X.in -2
- X.TP
- X\fIceiling\fP\ list\ max_messages
- XRestrict the number of messages processed daily for \fIlist\fP to
- X\fImax_messages\fP; this includes posted and rejected messages.
- X.TP
- X\fIremote\fP\ alias\ email-addr\ listproc-addr\ [host\ [port]]\ #Comment
- XThis makes a remote list known to the server. A remote list is another
- Xmailing list served by another server, and your server is now capable
- Xof forwarding to the proper remote list processor any requests sent about
- Xthis remote list to your server. \fIalias\fP is the name by which the remote
- Xlist is known by, \fIemail-addr\fP is the full email address of the
- Xremote list, \fIlistproc-addr\fP is the full email address of the
- Xremote list processor, and \fI#Comment\fP
- Xwill be used upon a \fIlists\fP request made to this server (the pound
- Xsign is mandatory). \fIhost\fP is either the DNS name or IP address
- Xof the remote server, used to connect to that server when a live request
- Xrefers to that list; the \fIport\fP should be specified if not the default
- X(372) (see \fIserverd\fP(1)).
- X.sp
- XRemote lists may have the same \fIalias\fP and they should not be confused
- Xwith peer lists. However, each remote list should be defined only once.
- XSee the discussion about PEER\ SERVERS (\fIlistproc\fP(1)) for further information.
- X.TP
- X\fIfax\fP fax-program options
- XDefine the fax program to use for \fIfax\fP requests (if any) and any
- Xcommand line options the program may use. The program should also be capable
- Xof accepting the file to fax from its standard input; otherwise a script
- Xwill have to be used instead which will in turn use the fax program
- Xappropriately. If this directive is left or commented out, then \fIfax\fP
- Xrequests are automatically turned off.
- X.sp
- XThe actual faxing program is called as follows:
- X.sp
- X.ce
- X\fIfax-program\fP \fIoptions\fP fax-number < file
- X.sp
- XThis request may not be issued from a live session, since fax programs work
- Xon email messages and extract the sender's address for reference when sending
- Xthe cover page of the fax.
- X.TP
- X\fIunix_cmd\fP\ list_alias\ password\ name\ \'unix-command\ [args]\'\ #Comment
- XAllow a \fIlist_alias\fP's subscribers only to execute the above
- X\fIunix-command\fP aliased to \fIname\fP. The \fIpassword\fP is made known
- Xto users who are to be given this privilege. The oprional \fIargs\fP may be
- Xliteral arguments to the command as well as the special sequences \fI$n\fP,
- Xwhere \fIn\fP is a digit from 1 to 9, or *; their meaning is that of the Bourne
- Xshell, and they will be substituted by the user's actual arguments. For
- Xexample:
- X.sp
- X.ce
- Xunix_cmd ermis pass1 swap \'/bin/echo $2 $1\' #Syntax: swap <arg1> <arg2>
- X.sp
- Xwill swap the user's first and second arguments. The user would submit a
- Xrequest that could look like this:
- X.sp
- X.ce
- Xrun ermis pass1 swap arg1 arg2
- X.sp
- XNo security checks are made except to ensure that the arguments contain no `, |,
- X:, < and >, so the \fImanager\fP is encouraged to review
- Xand verify the proper functioning of \fIunix-command\fP. The \fIComment\fP
- Xis used when users issue \'run <list>\' query requests.
- X.TP
- X\fIserverd\fP\ command-line-options
- XThis defines the command line options that \fIstart\fP(1) is to use
- Xwhen spawning \fIserverd\fP(1).
- X.TP
- X\fIrestriction\fP\ nusers
- XIf a restriction is placed on a ListProcessor request (via a -r command line
- Xoption to \fIlistproc\fP(1)), this directive defines the threshold number of users,
- Xabove which the restriction will take effect.
- X.TP
- X\fIdisable\fP\ list_alias request
- XThe specified server \fIrequest\fP is disabled for the specified list, and
- Xall such requests for this list are rejected, except when issued by privileged
- Xusers (list owners). The \fIlist_alias\fP has to
- Xbe defined (via a \fIlist\fP directive) before any requests can
- Xbe disabled.
- X.TP
- X\fImanager\fP\ full-email-address
- XThis defines the recipient of all system error messages, and the system's
- Xadministrator and caretaker; \fIfull-email-address\fP
- Xcan be any valid user name that can be reached via email by your system.
- XThe \fImanager\fP is usually the person responsible for the server
- Xaccount.
- X.TP
- X\fIcomment server\fP\ #Actual comment
- X.TP
- X\fIcomment\fP\ list_alias\ #Actual comment
- XA 'X-Comment:' line is included in every outgoing list/server message, and the
- Xtext following the pound sign will be copied every time; note that the pound
- Xsign is mandatory for the definition but will not be part of the actual string.
- XA list's comment is also used for the \fIlists\fP request to
- Xspecify the purpose of the particular mailing list. No 'X-Comment:' line
- Xis included if this directive is not defined for the particular list and/or
- Xserver.
- X.TP
- X\fIdigest\fP\ list_alias\ lines\ hours
- XIf any subscriber to the list requests digests, a digest will be sent when
- Xits length exceeds \fIlines\fP, or when \fIhours\fP have passed
- Xwithout a digest being sent. Digests for a list are collected only if at
- Xleast one of its subscribers has set his mail mode to \fIdigest\fP.
- X.TP
- X\fIarchive\fP\ list_alias\ dir\ filename\ [archive]\ [password]\ [digest]
- XRequest that all public messages are automatically archived; \fIlist_alias\fP
- Xis the list's name, \fIdir\fP is the directory that the archived
- Xfiles will be located (a full path has to be specified, and the directory
- Xhas to be writable by the server uid), \fIarchive\fP is the archive's name
- Xand is a relative path under the default archive (listproc) or "-" for the
- Xdefault, \fIpassword\fP is an optional password ("-" if none) to be used
- Xif the archive is meant to be private, and the optional
- Xkeyword \fIdigest\fP will force only digests to be archived; \fIfilename\fP
- Xspecifies the format of the archived files, and may contain any lower case
- Xcharacters and numbers, as well as the following special sequences:
- X.in +2
- X.sp
- X%m: Numeric month (01 - 12)
- X.sp
- X%d: Numeric day of the month (01 - 31)
- X.sp
- X%y: Year (00 - 99)
- X.sp
- X%j: Julian date (001 - 366)
- X.sp
- X%h: Month name (Jan - Dec)
- X.sp
- X%a: Contents of the Archive-Name: header line, if present; cannot be used if
- Xarchiving digests. The Archive-Name: header line has to be manually inserted
- Xby the sender of the message; it may show up in the body of the message as
- Xwell.
- X.sp
- X%#: Digest number; can only be used if archiving digests.
- X.sp
- X%1: First word of the first non-blank line of the message.
- X.sp
- X%v: Volume number, if the message contains a 'Volume # Number #' line before
- Xthe actual message.
- X.sp
- X%n: Issue number, if the message contains a 'Volume # Number #' line before the
- Xactual message.
- X.sp
- X%%: The character %
- X.in -2
- X.sp
- XFor example, to archive messages daily:
- X.sp
- X.ce
- Xarchive ermis HOMEDIR/archives/lists/ermis %y%m%d listproc/lists/ermis
- X.sp
- Xor to archive only files sent to the list:
- X.sp
- X.ce
- Xarchive venus /ftp/lists/venus vol-%v.num-%n listproc/lists/venus johny-be-good
- X.sp
- Xand in this case the sender that wants a file to be archived would precede
- Xit with a line similar to:
- X.sp
- X.nf
- XVolume 10 Number 5
- X.fi
- X.sp
- Xfollowed by the actual file.
- X.sp
- XWhen a new archive file is created, the Subject: line is used as the short
- Xdescriptive message for the archive.
- X.TP
- X\fIfrequency\fP\ seconds
- XHow often should \fIserverd\fP(1) check for new mail. When \fIseconds\fP is
- Xset to zero, \fIserverd\fP does not sleep.
- X.TP
- X\fIbatch\fP\ start\ stop
- XSpecify the hours (in military time) when requests are to be batched.
- XThe defaults are 8 and 20. \fIstart\fP and \fIstop\fP should be within
- Xthe same day (e.g. 8 am and 1 am the following day are not valid).
- X.TP
- X\fIlimit\fP\ keyword\ arguments
- XUsed to set certain limits in the system; \fIkeyword\fP can be:
- X.in +2
- X.sp
- X\fImessage\fP: limit the size of distributed messages to a certain
- Xnumber of bytes, which is the \fIargument\fP following this keyword.
- XA notification is sent back to the sender when this limit is exceeded,
- Xincluding the first few lines of his/her original message for reference.
- X.in -2
- X.sp
- X.in +2
- X\fIfiles\fP: limit the size of archive files that can be sent out to a certain
- Xnumber of bytes, which is the \fIargument\fP following this keyword.
- XWhen this limit is reached, the file is automatically split into subparts.
- X.TP
- X\fIprecedence\fP\ string
- XThe header of each outgoing message contains a Precedence: line; \fIstring\fP
- Xcan be:
- X.in +2
- X.sp
- Xbulk, junk, first-class, none: primarily used for vacation programs.
- X.in -2
- X.TP
- X\fIoption\fP\ keyword
- XThis defines a series of system-dependent options; \fIkeyword\fP can be:
- X.in +2
- X.sp
- X\fIsysv_ps\fP: the system will assume a System V version of ps(1).
- X.sp
- X\fIbsd_ps\fP: the system will assume a BSD version of ps(1).
- X.sp
- X\fIbsd_mail\fP: define it if BSD (UCB) mail is available on your system; if this
- Xis the case, make sure that /usr/ucb/mail is the path (or a link) to it; also
- Xsee src/Makefile.
- XThis is used to notify the \fImanager\fP of any error conditions.
- X.sp
- X\fIbad_telnet\fP: if the mail method used (see below) is \fItelnet\fP and
- Xthe system seems to send out only one message and then go to sleep, use
- Xthis option.
- X.sp
- X\fIpost_mail\fP: this will force the system to post messages to news
- Xgroups (using \fIinews\fP), using the groups' names (e.g. misc.test). Make
- Xsure that \fIinews\fP resides in /usr/lib/news, or
- X/usr/lib/news/inews is a link to it (also see src/Makefile).
- X.sp
- X\fIgate_mail\fP: this will force the system to gate messages to news, using
- Xthe gateways' email addresses.
- X.sp
- X\fIignore_invalid_requests\fP: ignore all unrecognized user requests and
- Xprocess valid ones only; by default, the system aborts processing requests
- Xupon the first invalid one, in which case a reply is sent to the user and
- Xall subsequent requests are flushed.
- X.sp
- X\fIrelaxed_syntax\fP: by default, the system complains when a request is
- Xgiven more arguments than expected. This turns such checking off.
- X.in -2
- X.TP
- X\fImailmethod\fP\ method\ [arguments]
- XEvery outgoing
- Xmessage should begin with a line of the form:
- X.in +2
- X.sp
- XFrom listproc@your-domain
- X.sp
- Xor
- X.sp
- XFrom list_alias@your-domain
- X.sp
- X.in -2
- Xwhich depends on the mail \fImethod\fP used:
- X.in +2
- X.sp
- X\fIsystem\fP: the recommended method; it provides a unified approach to
- Xsending mail and it has been ported and tested on lots of systems (see
- Xthe section PORT\ SPECIFIC below).
- XIn addition, since a full set of the SMTP protocol is implemented,
- X\fImanager\fP and list owners will be notified of invalid addresses and
- Xvarious system problems.
- XMoreover, mail will be queued when it cannot be delivered, in the
- Xdirectory HOMEDIR/mqueue; see \fIqueue(1)\fP for more information
- Xon how to process the mail queue.
- X.sp
- XThis method requires host TCP/IP and internet support; consult the
- Xsrc/README file for more information.
- X.sp
- X\fItelnet\fP: to be used only when \fIsystem\fP is inappropriate and telnet(1)
- Xis available on your host.
- X.sp
- X\fIenv_var\fP: usually followed by \fILOGNAME /bin/rmail\fP,
- Xor \fILOGNAME /usr/lib/sendmail -ba\fP (-ba is mandatory) -- to be
- Xused only when the previous methods are inappropriate.
- X.in -2
- X.SH MAIL\ LOOPS
- XThe system uses the following protocol for avoiding mail loops between
- Xa list and news connections: In the header of the outgoing message an
- X"Originator: " field is added. For each list plus listproc, a log of
- Xthe most recent (500) Message-Id's is kept.
- XWhenever a message is received, the
- XOriginator, Reply-To and Message-Id fields are extracted and looked up in
- Xthe ".ignored" and ".message.ids"
- Xfiles in the list's subdirectory. Gateways that feed back to the list
- Xshould preserve at least the Reply-To and Message-Id fields. The Originator
- Xand Message-Id fields are preserved by this system. A new Reply-To is
- Xtacked on when redistributing mail locally from a peer or a news feed.
- X.PP
- XTo avoid mail loops when forwarding ListProcessor requests to peers, the system
- Xlooks up the Message-Id field in the ".message.ids" file in
- XHOMEDIR.
- XIf this field is not preserved by the peer ListProcessor, it is suggested that you
- Xturn off request forwarding when connecting with peers served by such
- Xsystems, until a unified approach is taken. The Message-Id field is preserved
- Xby this ListProcessor. This system is also using a special Subject field,
- Xtotally proprietary and non-standard, in order to avoid unnecessary
- Xforwarding of requests, thus cutting down on email traffic.
- X.PP
- XIn addition, the system searches incoming messages for Message-Ids in the
- Xmessage body, as well as the occurence of the X-Listprocessor-Version header
- Xline in it, since most bounced messages include the entire original message.
- X.PP
- XFinally, a checksum for each incoming message is obtained and looked up
- Xagainst a database of the 500 most recent sums in the file ".sums" in the
- Xlist's subdirectory.
- X.SH CRASH\ RECOVERY
- XIt is possible that a message delivery was interrupted by a user
- X(\fIstart -k\fP), or by the system (crash/reboot). A built-in mechanism
- Xguarrantees to pick up delivery again from where it left off, if the
- Xsystem is restarted using \fIstart\fP(1). Both \fIstart\fP(1) and \fIlist\fP(1)
- Xreport to the effect that mail delivery was interrupted and will
- Xresume. On the other hand, processing of interrupted requests will not
- Xresume and all unprocessed requests will be lost.
- X.SH COMMUNICATING
- XUsers send requests to \fIlistproc@your-domain\fP and public messages to the
- Xvarious \fIlist_alias@your-domain\fP.
- X.SH ARCHIVES
- XThe server has an archiving capability of files. Archives may be public
- Xso that anyone can get files from them, or private so that only privileged
- Xusers may obtain files from them. There is a master archive
- Xin HOMEDIR/archives/listproc where all subarchives are defined. The archives
- Xkeep lists of files that are available to users via a \fIget\fP request, and
- Xindex of subarchives that are available to users via an \fIindex\fP
- Xrequest.
- X.PP
- XAs outlined in \fIlist\fP(1), each list's public messages are
- Xautomatically saved under the list's subdirectory in the file \fIarchive\fP.
- XThis file may periodically be placed in the system's archives by hand (if not
- Xarchiving automatically via the \fIarchive\fP directive), or may point to
- X/dev/null. The archived files may not necessarily reside in
- Xthe archive directories, as long
- Xas the archives know where they are located. See the man page for
- X\fIfarch(1)\fP for more information.
- X.PP
- XAlternatively, messages may be automatically archived via the \fIarchive\fP
- Xdirective in the \fIconfig\fP file.
- X.SH HELP
- XThe system comes configured with default help topics the recognized
- Xrequests. More topics may be added by editing the file
- XHOMEDIR/help/TOPICS, adding the topic(s) and the file(s) where the
- Xactual text exists.
- X.PP
- XHelp files may be simple text files or shell scripts, in which case they
- Xhave to start with "#!" in the first line and be followed by the path
- Xto the shell to be used; for example: #!/bin/sh
- X.SH SYSTEM\ MAINTENANCE
- XAs mentioned below, all programs report to certain files. The system's
- Xmanager should periodically check the files HOMEDIR/.report.server
- Xand the various HOMEDIR/lists/*/.report.list for any problems.
- XAll messages sent are saved under HOMEDIR/mbox and
- XHOMEDIR/lists/*/mbox and they should be cleaned up periodically.
- XFor debugging purposes, various warnings are written to
- XHOMEDIR/.warning; this file, as well as HOMEDIR/.report.catmail
- Xare shrunk every time \fIstart\fP(1) is run.
- X.PP
- XFor whenever the necessity arises to administer the system remotely, the
- Xfollowing scheme may be used to start or kill the system, process the mail
- Xqueue, force an application to execute immediately, etc: a mail message
- Xis sent to an alias whose sole role is to fire up an application; the
- Xapplication has to have been setuid before.
- X.PP
- XFor instance, to start the
- Xsystem remotely, you may set up an alias such as:
- X.sp
- X.nf
- X.in +2
- Xstart-server: "|HOMEDIR/start -cr > /dev/null"
- X.in -2
- X.fi
- X.sp
- XTo kill the system, you may define another alias:
- X.sp
- X.nf
- X.in +2
- Xkill-server: "|HOMEDIR/start -crk > /dev/null"
- X.in -2
- X.fi
- X.sp
- XTo force requests to get processed now:
- X.sp
- X.nf
- X.in +2
- Xrun-listproc: "|HOMEDIR/listproc -1 > /dev/null"
- X.in -2
- X.fi
- X.sp
- XTo start the queue daemon:
- X.sp
- X.nf
- X.in +2
- Xproc-queue: "|HOMEDIR/queued 60 & > /dev/null"
- X.in -2
- X.fi
- X.sp
- XThese aliases should be hard to guess for obvious reasons. The actual
- Xmessage sent to such an alias is discarded.
- X.SH EXIT\ CODES
- XAll applications except tlock use the following exit codes for communication:
- X.sp
- X.TP
- X0
- X- OK, normal exit
- X.TP
- X1
- X- Could not open or lock file
- X.TP
- X2
- X- SIGINT signal (normal termination)
- X.TP
- X3
- X- Command line option error
- X.TP
- X4
- X- Syntax error in file
- X.TP
- X5
- X- Could not spawn (restart failed)
- X.TP
- X6
- X- Shutdown request
- X.TP
- X7
- X- Restart request
- X.TP
- X8
- X- Received system signal (anything but SIGINT will bring the system down)
- X.TP
- X9
- X- Too many multiple recipients
- X.TP
- X10
- X- Could not deliver mail (unexpected reply during the SMTP transaction)
- X.TP
- X11
- X- malloc() failed
- X.TP
- X12
- X- Cannot fork()
- X.TP
- X13
- X- Socket connection problem
- X.TP
- X14
- X- Semaphore error
- X.TP
- X15
- X- Cannot setuid()/setgid()
- X.TP
- X16
- X- Internal error or system call failure
- X.fi
- X.PP
- Xtlock exits with:
- X.TP
- X-1
- X- File locking not functional
- X.TP
- X0
- X- No files locked
- X.TP
- X1
- X- Cannot open config
- X.TP
- X2 & up
- X- Number of files locked + 1
- X.SH REPORTS
- XThe system provides two ways of reporting progress: via syslog(3) when available
- X(by compiling with -DSYSLOG=facility) with priority LOG_INFO and facility as
- Xspecified, or through its own report files (when not using syslog(3)); these
- Xare:
- X.TP
- XHOMEDIR/.report.catmail
- XMessages from \fIcatmail\fP(1) every time new messages are appended to the
- Xvarious mail files.
- X.TP
- XHOMEDIR/.report.daemon
- XMessages from \fIserverd\fP(1) every time new mail has arrived.
- X.TP
- XHOMEDIR/.report.list
- XError messages from \fIlist\fP(1) when attempting to process public messages.
- X.TP
- XHOMEDIR/.report.pqueue
- XMessages from \fIpqueue\fP (see \fIqueue\fP(1)).
- X.TP
- XHOMEDIR/.report.server
- XMessages from \fIlistproc\fP(1) every time new requests are processed.
- X.TP
- XHOMEDIR/.report.start
- XGenerated by \fIstart\fP(1) every time the system is started.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.report.list
- XMessages from \fIlist\fP(1) when processing public messages.
- X.TP
- XHOMEDIR/.*.acc
- XAccumulated reports since the system was first installed.
- X.TP
- XHOMEDIR/lists/*/.*.acc
- XAccumulated reports for each mailing list.
- X.PP
- XEvery report includes a time stamp; every list and server report also
- Xincludes the actual sender of the message, and every server report
- Xincludes all requests made by the sender.
- X.PP
- XWhenever a program dies abnormally (and BSD mail is present) a message
- Xis sent to \fImanager\fP (as defined in \fIconfig\fP).
- XThe message is usually sent by \fIserverd\fP(1) which
- Xthen exits. The daemon dies with a different message according to the exit
- Xstatus of the child; the various error conditions that may occur are:
- X.TP
- XCould not open file
- XHOMEDIR is not a valid path; file was accidentally deleted;
- Xinsufficient access privileges. Run \fIsetup\fP and \fIstart\fP.
- X.TP
- XCould not lock file
- XHOMEDIR is not a valid path; file was accidentally deleted;
- Xinsufficient access privileges; another program is using the lock
- Xfile. Run \fItlock\fP, and if necessary, \fIulock\fP; then \fIstart\fP.
- X\fItlock\fP checks for locked files, and \fIulock\fP removes all lock
- Xfiles.
- X.TP
- XCommand line option error
- XCheck the \fIconfig\fP file and restart.
- X.TP
- XSyntax error in file
- XCheck \fIconfig\fP, all reports, .subscribers, .peers and .news files.
- X.TP
- XCould not spawn
- XNo more processes.
- X.TP
- XReceived system signal
- XSIGQUIT, SIGTERM, SIGBUS, SIGSEGV, SIGILL.
- X.SH FILES
- X.TP
- XHOMEDIR/.aliases
- XAliases of email addresses of users having trouble getting replies to requests.
- X.TP
- XHOMEDIR/.awk
- Xawk program for formatting the \fIstatistics\fP request.
- X.TP
- XHOMEDIR/.grep
- Xscript used for counting the number of messages sent by a subscriber.
- X.TP
- XHOMEDIR/.ignored
- XList of unwanted senders.
- X.TP
- XHOMEDIR/.lock.pqueue
- XLock file for \fIpqueue\fP (see \fIqueue\fP(1)).
- X.TP
- XHOMEDIR/.lock.serverd
- XLock file for \fIserverd\fP(1).
- X.TP
- XHOMEDIR/.message.ids
- XA database of recent message id's used to detect mail loops.
- X.TP
- XHOMEDIR/.queue.id
- XNext id to be assigned to next undeliverable message placed in the mqueue/
- Xdirectory.
- X.TP
- XHOMEDIR/.reply.listser
- XThe reply code given to \fIserverd\fP(1) during a live session.
- X.TP
- XHOMEDIR/.rep.server.acc
- XArchived \fIlistproc\fP(1) reports.
- X.TP
- XHOMEDIR/.rep.serverd.acc
- XArchived \fIserverd\fP(1) reports.
- X.TP
- XHOMEDIR/.rep.start.acc
- XArchived \fIstart\fP(1) reports.
- X.TP
- XHOMEDIR/.report.catmail
- XCurrent \fIcatmail\fP(1) report.
- X.TP
- XHOMEDIR/.report.daemon
- XCurrent \fIserverd\fP(1) report.
- X.TP
- XHOMEDIR/.report.list
- XError messages from \fIlist\fP(1).
- X.TP
- XHOMEDIR/.report.server
- XCurrent \fIlistproc\fP(1) report.
- X.TP
- XHOMEDIR/.report.start
- XLast \fIstart\fP(1) action (system started or shut down).
- X.TP
- XHOMEDIR/.stats
- XScript used for the \fIstatistics\fP request.
- X.TP
- XHOMEDIR/.sums
- XDatabase of checksums of public messages.
- X.TP
- XHOMEDIR/.tag.id
- XNext id to be assigned to next moderated message.
- X.TP
- XHOMEDIR/.warning
- XLog of system calls' exit statuses.
- X.TP
- XHOMEDIR/batch
- XBatched user requests.
- X.TP
- XHOMEDIR/catmail
- XIncoming message redirection application.
- X.TP
- XHOMEDIR/config
- XThe configuration file.
- X.TP
- XHOMEDIR/farch
- XFile archiving utility.
- X.TP
- XHOMEDIR/ilp
- XInteractive ListProcessor client; to be used to connect to the
- Xinteractive server.
- X.TP
- XHOMEDIR/list
- XThe mailing list program.
- X.TP
- XHOMEDIR/listproc
- XThe system's request server.
- X.TP
- XHOMEDIR/lost+found
- XRequests that could not be appended to HOMEDIR/requests.
- X.TP
- XHOMEDIR/mbox
- XAn archive of all requests sent to date to ListProcessor.
- X.TP
- XHOMEDIR/news
- XScript used to add a news group to a list.
- X.TP
- XHOMEDIR/owners
- XList of list owners' addresses used for authentication of list maintenance
- Xrequests.
- X.TP
- XHOMEDIR/peer
- XScript used to add a peer list.
- X.TP
- XHOMEDIR/pqueue
- XThe mail queue processing program (see \fIqueue(1)\fP).
- X.TP
- XHOMEDIR/priv.hosts
- XList of hosts that may connect to the interactive part of the system.
- X.TP
- XHOMEDIR/queued
- XThe mail queue processing daemon (see \fIqueue(1)\fP).
- X.TP
- XHOMEDIR/received
- XFile containing the messages received from sendmail during the
- Xlast message distribution -- the \fIsystem\fP mailmethod has to be
- Xin use.
- X.TP
- XHOMEDIR/requests
- XNewly arrived user requests.
- X.TP
- XHOMEDIR/requests.live
- XRepository for requests coming in from live connections.
- X.TP
- XHOMEDIR/sent
- XFile containing the messages sent to sendmail during the
- Xlast message distribution -- the \fIsystem\fP mailmethod has to be
- Xin use.
- X.TP
- XHOMEDIR/serverd
- XThe system's daemon.
- X.TP
- XHOMEDIR/setup
- XSystem setup script.
- X.TP
- XHOMEDIR/start
- XThe system's housekeeping program.
- X.TP
- XHOMEDIR/tlock
- XChecks for any locked files.
- X.TP
- XHOMEDIR/ulock
- XScript to remove all lock files.
- X.TP
- XHOMEDIR/unwanted.hosts
- XList of hosts that may not connect to the interactive part of the system.
- X.TP
- XHOMEDIR/welcome.live
- XWelcoming message upon live connection establishment.
- X.TP
- XHOMEDIR/archives/listproc/DIR
- XDirectory of all files available from the master archive (listproc).
- X.TP
- XHOMEDIR/archives/listproc/INDEX
- XThe master archive index.
- X.TP
- XHOMEDIR/doc/catmail.1
- XMan page source for \fIcatmail\fP(1).
- X.TP
- XHOMEDIR/doc/catmail.nr
- XFormatted man page for \fIcatmail\fP(1).
- X.TP
- XHOMEDIR/doc/farch.1
- XMan page source for the \fIfarch\fP(1) utility.
- X.TP
- XHOMEDIR/doc/farch.nr
- XFormatted man page for the \fIfarch\fP(1) utility.
- X.TP
- XHOMEDIR/doc/ilp.1
- XMan page source for the \fIilp\fP(1) utility.
- X.TP
- XHOMEDIR/doc/ilp.nr
- XFormatted man page for \fIilp\fP(1).
- X.TP
- XHOMEDIR/doc/list.1
- XMan page source for \fIlist\fP(1).
- X.TP
- XHOMEDIR/doc/list.nr
- XFormatted man page for \fIlist\fP(1).
- X.TP
- XHOMEDIR/doc/listproc.1
- XMan page source for \fIlistproc\fP(1).
- X.TP
- XHOMEDIR/doc/listproc.nr
- XFormatted man page for \fIlistproc\fP(1).
- X.TP
- XHOMEDIR/doc/queue.1
- XMan page source for \fIpqueue\fP and \fIqueued\fP(1).
- X.TP
- XHOMEDIR/doc/queue.nr
- XFormatted man page for \fIpqueue\fP and \fIqueued\fP(1).
- X.TP
- XHOMEDIR/doc/server.1
- XSource of the system's main man page.
- X.TP
- XHOMEDIR/doc/server.nr
- XFormatted main man page.
- X.TP
- XHOMEDIR/doc/serverd.1
- XMan page source for \fIserverd\fP(1).
- X.TP
- XHOMEDIR/doc/serverd.nr
- XFormatted man page for \fIserverd\fP(1).
- X.TP
- XHOMEDIR/doc/start.1
- XMan page source for \fIstart\fP(1).
- X.TP
- XHOMEDIR/doc/start.nr
- XFormatted man page for \fIstart\fP(1).
- X.TP
- XHOMEDIR/help/*
- XGeneral and topic-specific help files available upon a \fIhelp\fP
- Xrequest. The TOPICS is a special file where topics are defined.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.aliases
- XAliases of email addresses of subscribers.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.digest.toc
- XAll the subject lines from the digest. It will be
- Xwritten at the head of the digest when it is sent.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.digest.msg
- XAll the messages of the digest, separated by dashed lines.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.digest.time
- XThe time that the last digest was sent, represented as the value
- Xreturned by time(2). It is used to calculate when it is time to send
- Xout the next digest.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.headers
- XAn archive of who sent each message; used upon a \fIstatistics\fP
- Xrequest.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.ignored
- XA list of unwanted senders.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.info
- XText sent upon an \fIinformation\fP request.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.limits
- XUsed by \fIserverd\fP(1) when placing various limits for the list.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.message.ids
- XA database of recent message id's used to detect mail loops.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.news
- XA list of all news groups connected to this list.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.peers
- XA list of all peer lists for this mailing list,
- Xalong with the email addresses of their servers.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.rep.list.acc
- XArchived reports from \fIlist\fP(1).
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.report.list
- XCurrent report from \fIlist\fP(1).
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.restricted
- XList of subscribers with alternate recipient files.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.subscribers
- XA list of all subscribers along with preferences and settings.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.un.digest
- XWhen a digest is constructed, it will be stored in this file until it
- Xhas been sent to all digest subscribers.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/.welcome
- XText sent on a \fIsubscribe\fP request.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/archive
- XArchive of all distributed messages since the file was last created.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/lost+found
- XMail that could not be appended to the 'mail' or 'moderated' files
- X(see next entries and \fIcatmail\fP(1)).
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/mail
- XNewly arrived public messages to be distributed.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/mbox
- XAn archive of all messages sent to date.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/moderated
- XNewly arrived public messages that need to be edited before
- Xdistributed.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/removed.users
- XEntries from the .subscribers file for users who have been automatically
- Xremoved from the list.
- X.TP
- XHOMEDIR/lists/LIST_ALIAS/removed.alias
- XEntries from the .aliases file for users who have been automatically
- Xremoved from the list.
- X.TP
- XHOMEDIR/mqueue/*
- XQueued messages for later delivery.
- X.SH UPGRADING
- XWhen upgrading, it is not necessary to remove your current system.
- XOld key directories and files will be moved elsewhere. Always run the
- X\fIsetup\fP script. In addition, if you are upgrading from:
- X.TP
- X5.5
- XThe system may now go interactive with the -i flag to \fIserverd\fP(1).
- X.sp
- X\fIremote\fP lists may now specify host names or Internet addresses and ports if
- Xthey are served by interactive ListProcessors.
- X.sp
- XThe ULISTPROC_UMASK environment variable is now used. For archives, there is
- XULISTPROC_ARCHIVES_UMASK.
- X.sp
- XThe IUL (\fIilp(1)\fP) client is available to connect to interactive
- XListProcessors.
- X.sp
- XThe \fIhelp\ live\fP request explains how to connect to interactive
- XListProcessors.
- X.sp
- XThe \fIprecedence\fP directive has been added to the \fIconfig\fP file.
- X.sp
- XPrecious header lines are preserved for each list via the \fIheader\fP
- Xdirective.
- X.sp
- XRegular expressions are implemented for the ".aliases" and ".ignored" files.
- X.sp
- XLists may now automaticlly archive distributed messages via the
- X\fIarchive\fP directive.
- X.sp
- XThe manager may allow subscribers of a list to execute UNIX commands via the
- X\fIunix_cmd\fP directive. Users submit a \fIrun\fP request in this case
- X(CCRUN is added as a preference).
- X.sp
- X\fIfarch\fP now creates new archives and takes care of updating and creating
- XDIR and INDEX files as well as directories, and may archive true binary files
- X(does not uuencode them) if requested (-B flag); the -p option was introduced
- Xto accept a password for a new private archive, the -D option to specify
- Xa short description of the files, and the -r option to remove files from
- Xarchives.
- X.sp
- XCommands in the \fIconfig\fP file may span multiple lines if each line is
- Xterminated by &\\n.
- X.sp
- XThe system intercepts requests sent to lists.
- X.sp
- XThe \fIconceal\fP user attribute has been introduced to the subscribers files.
- X.sp
- XThe \fIdefault\fP directive has been introduced to the \fIconfig\fP file to
- Xset default values for new subscribers.
- X.sp
- XUsers may change the address they are subscribed with, if the owner allows this.
- X.sp
- XThe util/ directory has been introduced for general utilities.
- X.sp
- XHelp files may now be shell scripts; same for all lists' ".welcome" and
- X".info" files.
- X.sp
- Xsyslog(3) is now supported for progress reporting by compiling with
- X-DSYSLOG=facility.
- X.sp
- XArchive files may be split on the way out if they exceed the \fIlimit\fP
- Xspecified in the \fIconfig\fP file.
- X.sp
- XLists may restrict the number of messages processed per day with the
- X\fIceiling\fP directive.
- X.sp
- XThe new request \fIfax\fP with its synonymous directive have been introduced.
- X.sp
- XConcealed lists are supported via the -c option to \fIlistproc\fP(1).
- X.sp
- XError messages from mailer daemons are scanned and automatic action is taken
- Xif compiling with -DERROR_MAIL_ANALYSIS=level (1=conservative, 9=full).
- X.sp
- XArchives may now be searched with the \fIsearch\fP request.
- X.sp
- X\fIcatmail\fP will now time out after 2 minutes of idle time (perhaps
- Xdue to OS problems).
- X.sp
- XYou may now turn off compression of archived files and messaged with
- Xnew flags to \fIfarch\fP and \fIlist\fP.
- X.sp
- XRun the upgrade_to_6.0c script.
- X.TP
- X5.41
- XModerated lists are now owner controlled, rather than manager controlled.
- X.sp
- XManager preferences have now been introduced.
- X.sp
- XSee the UPGRADING section in \fIfarch(1)\fP.
- X.sp
- XFollow the upgrade instructions for 5.5
- X.TP
- X5.4
- X\fIcatmail\fP(1) has been implemented, therefore the various aliases
- Xin the aliases file have to be redefined (as explained above) to
- Xtake advantage.
- X.sp
- XOwner preferences have been introduced in the \fIowners\fP file.
- X.sp
- XFollow the upgrade instructions for 5.41
- X.TP
- X5.31
- XThe \fIlist\fP directive in the \fIconfig\fP file now takes two extra
- Xarguments: the list owner's address, and the list's access password.
- X.sp
- X\fIqueued\fP now takes only one argument, a frequency count.
- X.sp
- XThe system supports 10 lists by default (see LIMITATIONS below);
- Xif you are currently using the maximum supported number of lists, consult
- Xthe HOMEDIR/src/defs.h file.
- X.sp
- XThe layout and structure of INDEX files has been extended; see
- X\fIfarch(1)\fP for more information.
- X.sp
- XFollow the upgrade instructions for 5.4
- X.TP
- X5.3
- XThe \fIlist\fP directive in the \fIconfig\fP file now takes two extra
- Xarguments: the list owner's address, and the list's access password.
- X.sp
- XThe system supports 10 lists by default (see LIMITATIONS below);
- Xif you are currently using the maximum supported number of lists, consult
- Xthe HOMEDIR/src/defs.h file.
- X.sp
- XThe layout and structure of INDEX files has been extended; see
- X\fIfarch(1)\fP for more information.
- X.sp
- XFollow the upgrade instructions for 5.4
- X.TP
- X5.2\*
- XUse the \fIsystem\fP mailmethod.
- X.sp
- XFor every list you need to edit HOMEDIR/lists/LIST_ALIAS/.ignored
- Xand add one more entry: the full email address of the server account.
- X.sp
- XFollow the upgrade instructions for 5.3
- X.TP
- X5.0, 5.1\*
- XFor every list you need to edit
- XHOMEDIR/lists/LIST_ALIAS/.ignored and add
- Xtwo entries: the actual list alias, and the full email address
- Xof this list.
- X.sp
- X\fIneverack\fP is not a valid mail mode anymore. Change every
- Xoccurrence in ".subscribers" to NOACK, for every list.
- X.sp
- XAny peer lists and/or news groups appearing in ".subscribers"
- Xshould be removed; use the \fIpeer\fP and \fInews\fP scripts
- Xto put them back.
- X.sp
- X\fIserverd\fP, \fIlist\fP and \fIlistproc\fP no longer report to the
- Xstdout by default -- use the -e command line option.
- X.sp
- XFollow the upgrade instructions for 5.2
- X.SH PORT\ SPECIFIC
- XFor various compilation options, consult the src/Makefile.
- XStarting with version 5.3, a universal mailmethod was introduced: \fIsystem\fP;
- XIt should be used in every system that has TCP/IP installed,
- Xas it has been verified to work on
- Xmany systems below -- consult the src/README file.
- X.TP
- XIBM Risc
- XYou should use \fIsysv_ps\fP as an option in the \fIconfig\fP file,
- Xand compile with xlc -D_ALL_SOURCE -qnoro. You have to use \fIsystem\fP
- Xas the mailmethod. Messages distributed to local
- Xsubscribers on the system may see their messages arrive "From root...",
- Xbut all other subscribers in the outside world will see "From listproc@..."
- Xand/or "From list@..." which is the correct header. If you use
- X\fIenv_var\ LOGNAME\ /bin/rmail\fP instead, the behavior will be reversed.
- X\fItelnet\fP may not be used as a mailmethod. Compile with -DHAVE_SELECT_H,
- X-DHAVE_ULIMIT_H -DSETPGRP_NEEDS_ARGS and -DHAVE_SETJMP_H, and link with -lbsd.
- XIn defs.h the system is defined as having an SVR3 flavor.
- X.TP
- XSGI
- XYou have to use the \fIsystem\fP mailmethod.
- XAll Irix versions to date seem to have a serious problem with telnet (it
- Xcorrupts file descriptors). Use the \fIsysv_ps\fP option.
- XIn the Makefile, for IRIX 4, define the symbol CC to be 'cc -ansi' or 'cc
- X-D__STDC__', and compile with -DHAVE_SETJMP_H and -D_POSIX_SOURCE; for IRIX 5,
- Xcompile with 'cc -D_BSD_SOURCE -Dsvr4' and all other flags found by systest.
- XIn defs.h the system is defined as having an SVR3 flavor.
- X.TP
- XSUN
- X\fIsystem\fP and \fItelnet\fP work fine as mailmethods.
- XUse the \fIbsd_ps\fP option. The server user id should not be the same
- Xas root's.
- XIf you use the native cc compiler you will need to convert to K&R C
- X(by using the unproto system -- consult the src/Makefile);
- Xotherwise /usr/lang/acc -w (ANSI C) can be used. Compile with -DHAVE_SETJMP_H
- Xand -DSETPGRP_NEEDS_ARGS.
- XIn defs.h the system is defined as having a BSD flavor. On Solaris 5.2 and
- Xabove, compile with -Dsvr4 only. If using the live part of the system and
- Xyour host is a YP/NIS client you should put the new service in the master's
- Xservices map, or if on the master, remake the map. Older versions of SUNOS have
- Xproblems with their include files, and in this case you have to comment out
- Xthe line:
- X.sp
- X#include <netdb.h>
- X.sp
- Xin src/*.c
- X.TP
- XDECstations
- XYou have to use \fIsystem\fP as the mailmethod; if you use
- X\fItelnet\fP instead, you may have to use the \fIbad_telnet\fP
- Xoption; \fIbsd_ps\fP should be used. Ultrix 3.0 has lots of system bugs
- Xand you may experience strange behavior; the file locking mechanism
- Xover NFS appears to be non-standard and is disabled by default; upgrade to 4.2A
- Xis recommended.
- XAn ANSI C compiler should be used. If you are using the unproto system,
- Xuse the -nocpp flag to cc when compiling. Compile with -DHAVE_SETJMP_H and
- X-DSETPGRP_NEEDS_ARGS.
- XIn defs.h the system is defined as having a BSD flavor. All Bourne shell scripts
- Xmay need to be altered to invoke /bin/sh5, before they are used.
- X.TP
- XConvex
- XIt is suggested that you use the \fIstds\fP script (available via anonymous ftp
- Xfrom cs-ftp.bu.edu) and the non-ANSI compiler; \fIstds\fP should be used as follows:
- X.sp
- Xstds src/nonansi/*.h src/*.c
- X.sp
- XThis should be done after redefining the HOMEDIR entry in src/Makefile and
- Xrunning setup to make all the necessary changes. Compiling under
- XANSI standards (-std flag) is not recommended, since system
- Xinclude files are not ANSI-C compliant. The system cannot go interactive
- Xsince the system does not support semaphores. \fIsystem\fP works fine as
- Xa mailmethod. paste(1) is missing and \fIstatistics\fP requests will
- Xlook erroneous.
- X.TP
- XStardent GS series
- X\fIsystem\fP and \fItelnet\fP work fine as mailmethods.
- XUse the \fIsysv_ps\fP option. The unproto system has to be used (consult
- Xthe src/Makefile) if not using an ANSI C compiler. The system cannot
- Xgo interactive due to a system() bug. In defs.h the system
- Xis defined as having an SVR3 flavor.
- X.TP
- XStardent/KPC Titan series
- X\fIsystem\fP and \fIenv_var\ LOGNAME\ /bin/rmail\fP work fine as mailmethods.
- XUse the \fIsysv_ps\fP option. The system cannot go interactive due to the
- Xabsence of waitpid(), and compiling and linking with -43 (to use wait3())
- Xhangs \fIserverd(1)\fP and the other applications.
- XIn defs.h the system is defined as having an SVR3 flavor.
- X.TP
- XNeXT
- X\fItelnet\fP, \fIsendmail\fP, \fIsystem\fP (if TCP/IP is installed and SMTP is
- Xused) work fine as mailmethods; however, 'mailmethod sendmail
- X/usr/lib/sendmail -ba' has been characterized as a "DISASTER in terms of
- Xhogging the cpu." Compile with
- X-D__NeXT__ if your compiler does not define this symbol (under version 3.0
- Xof the OS this symbol is automatically defined -- 3.0 is the only supported
- Xenvironment). Compile with -I/usr/include/bsd and -I/usr/include/bsd/sys and
- X-DSETPGRP_NEEDS_ARGS.
- XFile locking is turned off because of an OS bug.
- XIn defs.h the system is defined as having a BSD flavor. The system
- Xcannot go interactive due to lack of semaphore support.
- X.TP
- XHP-UX
- XCompile with -Aa, -D_HPUX_SOURCE, -DHAVE_ULIMIT_H, -DHAVE_SETJMP_H.
- X\fIsystem\fP is the mailmethod to use.
- XIn defs.h the system is defined as having a BSD flavor.
- X.TP
- XSCO
- XCompile with -Dsco and possibly with -I/usr/include/netinet.
- XYou may wish to link with a
- Xspecial libbsd.a which can be obtained from /pub/sco-ports/libbsd on
- Xdribble.c-mols.siu.edu (131.230.93.2). You need to link with -lsocket.
- XIn defs.h the system is defined as having an SVR3 flavor. The port was done
- Xunder SCO version 3.2.4. The interactive part seems to hang for no apparent
- Xreason.
- X.TP
- XApollo
- XUse the \fIsystem\fP mailmethod. Do not compile with -A ansi, or if you do
- Xalso compile with -Dapollo. The OS that the port was performed under was
- XSR10.4 and version 6.8 of cc. The server id's path should include
- X/sys5.3/usr/bin so that 'paste' may be found. In defs.h the system is defined
- Xas having a BSD flavor. The system cannot go interactive due to lack of
- Xsemaphore support.
- X.TP
- XXenix
- XCompile with -Dxenix; grep(1) is buggy and is suggested that another version
- Xis used. In defs.h the system is defined as having an SVR3 flavor.
- X.TP
- XSequent
- XCompile with gcc -fwritable-strings and -Dsequent if the compiler does not
- Xdefine this symbol. In defs.h
- Xthe system is given a BSD flavor. If under Dynix/PTX, compile with -Dsvr3
- X(PTX is a a System V R3.2 implementation; V2.0.3 includes an ANSI C compiler).
- X.TP
- XData General
- XCompile using gcc -fwritable-strings; in defs.h the system is given an SVR4
- Xflavor and is advisable not to give it a BSD one; keep in mind that
- Xsignals frequently get lost.
- X.TP
- Xi860
- XThis is a standard SVR4 UNIX; \fIsystem\fP works fine as mailmethod. All
- Xfeatures are functional.
- X.TP
- Xi386
- XThis is a BSD environment; the system cannot go interactive due
- Xto lack of semaphore support, and file locking is turned off. \fIsystem\fP
- Xworks fine as mailmethod. Compile with the -fwritable-strings flag.
- X.TP
- XOSF
- XThis is a standard SVR3 UNIX; \fIsystem\fP works fine as mailmethod. All
- Xfeatures are functional. Compile with the -std1 flag. Do not compile with
- X-DHAVE_SELECT_H because of missing system header files, but compile with
- X-DSETPGRP_NEEDS_ARGS.
- X.TP
- XOther
- XFirst, attempt compiling with -Dunknown_port.
- X.SH LIMITATIONS
- X\-
- XUp to 10 mailing lists can be supported (configurable in
- Xsrc/defs.h and src/Makefile).
- X.sp
- X\-
- XThe system assumes a length of 32 bits or higher for long integers.
- X.sp
- X\-
- XA list alias may not be called "server".
- X.SH COMPILER
- X.TP
- Xgcc
- XIf you are using gcc to compile, use the -fwritable-strings flag. Versions
- Xprior to 2.2.1 may cause problems.
- X.SH MAILER
- X.TP
- XZmailer
- XIf you are using the Zmailer to send mail, or any other mailer (like Smail)
- Xthat requires a 'HELO hostname' to start the SMTP transaction,
- Xcompile with -DZMAILER (also see src/README and src/Makefile).
- X.SH REQUIREMENTS
- XThe $path for the server account should include all necessary paths to
- Xcut(1), paste(1), awk(1), grep(1), uptime(1) and telnet(1).
- XIn addition, uptime(1) should report the number of users and the system
- Xload; otherwise \fIserverd\fP(1) cannot be run with the -l option, and
- X\fIlistproc\fP(1) cannot be run with the -r option. The output from uptime
- Xshould look like:
- X.nf
- X.sp
- X12:45pm up 5 days, 16 mins, 4 users, load average: 0.00, ...
- X.sp
- X.fi
- XAlso, make sure that when posting, /usr/lib/news/\fIinews\fP exists either
- Xas itself or as a link to wherever \fIinews\fP resides (also see src/Makefile).
- X.sp
- XFinally, grep(1) should support the -i (case insensitive matching) and
- X-v (print all lines that do not match the expression) flags.
- X.SH BUGS
- X.TP
- Xuptime
- XWhen user and load restrictions are enforced, the system assumes
- Xthat uptime outputs a line similar to the one shown above.
- X.TP
- Xblanks
- XAlthough the system handles email addresses with blanks in them fairly
- Xwell, \fIstatistics\fP, \fIrecipients\fP and \fIset\ list\fP (status
- Xquery) requests will show erroneous results for these users.
- X.TP
- Xspecial characters
- XThe system does not accept addresses that contain single quotes, back-quotes
- Xor wild characters.
- X.TP
- Xmessages exceeding limits not caught
- XWhen all subscribers of a list have set their mail mode to \fIdigest\fP,
- Xmessages are not subject to size limitations.
- X.TP
- Xno \fIstatistics\fP request for NeXT 2.1 hosts
- XDue to the absense of cut(1) the \fI.stats\fP script has to be
- Xmodified to replace the use of cut(1) with awk(1).
- X.TP
- X\fIserverd\fP(1) dies with 'no tty' error message
- XIn the \fIconfig\fP file use the -e flag in the \fIlist\fP, \fIserver\fP and
- X\fIserverd\fP definitions followed by '> /dev/null 2>&1'. For example:
- X.sp
- X.ce
- Xserverd -i 600 -e > /dev/null 2>&1
- X.TP
- Xincorrect auto-splitting of files on the way out
- XWhen splitting files that exceed the specified limit, the system precalculates
- Xthe number of parts it will send and puts this number in the Subject: line.
- XHowever, since each part may actually be less than that limit (each part
- Xextends to the nearest newline without exceeding the limit) it is possible to
- Xsend more parts than predicted, if the total number of bytes backtracked (for
- Xall parts) is an integer multiple of the limit; in this case the number of
- Xextra parts will be this integer multiple. The probability of this happening
- Xincreases as the limit is decreased.
- X.SH SEE\ ALSO
- Xcatmail(1), farch(1), ilp(1), list(1), listproc(1), queue(1), serverd(1),
- Xstart(1)
- X.SH AUTHOR
- X.nf
- XAnastasios C. Kotsikonas
- XCopyright (c) 1991-93, Anastasios Kotsikonas
- XComments to tasos@cs.bu.edu
- X.fi
- *-*-END-of-doc/server.1-*-*
- echo x - doc/serverd.1
- sed 's/^X//' >doc/serverd.1 <<'*-*-END-of-doc/serverd.1-*-*'
- X.\" ListProcessor System
- X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
- X.\"
- X.TH serverd 1 "ListProcessor"
- X.SH NAME
- X\fBserverd\fP \- ListProcessor system daemon
- X.SH SYNOPSIS
- X\fBserverd\fP [\fB-1\fP] [\fB-e\fP] [\fB-l load\fP] [\fB-i duration\fP]
- X.SH DESCRIPTION:
- X\fIserverd\fP silently looks for any new messages for the request
- Xserver and for any of the supported mailing lists, checks whether
- Xthe time has arrived for processing the batch queue, whether
- Xdigest time has been reached for the various lists, and whether any
- Xlive TCP/IP connections are requested. It then spawns
- X\fIlistproc\fP(1) and/or \fIlist\fP(1) as necessary, and sleeps until the
- Xmessage(s) is (are) processed. \fIserverd\fP reads the \fIconfig\fP file
- X(see \fIserver\fP(1)).
- X.SH OPTIONS
- XThe following command line options are recognized:
- X.TP
- X-1
- XExecute only once -- to be used with cron(1).
- X.TP
- X-e
- XEcho reports to the screen; it has no effect if the system has been compiled
- Xwith -DSYSLOG.
- X.TP
- X-l load
- XEnforce load restrictions; \fIserverd\fP will postpone spawning if the
- Xsystem load is above the limit specified.
- X.TP
- X-i duration
- XA child process is also spawned which listens for live TCP/IP connections
- Xat port 372 (this is referred to as the Listsener process, and its parent as
- Xthe Master); for each such connection a child process is created to
- Xprocess the live requests (see the INTERACTIVE\ LISTPROC section below). The
- Xmaximum \fIduration\fP time is given in seconds.
- X.SH INTERACTIVE\ LISTPROC
- XProvided that the host supports the TCP/IP protocol, the system provides
- Xa mechanism for processing live requests by specifying the -i flag to
- X\fIserverd\fP. Any user may use \fItelnet\fP(1) to connect to a host
- Xthat runs this system at port number 372, issue requests as he would
- Xby email, and receive responses immediately. However, the proper way
- Xto connect to the server is by using \fIilp\fP(1) which lets the user download
- Xfiles through \fIget\fP requests, and provides other amenities as well.
- X.PP
- XWhat requests are allowed
- Xdepends on the privileges assigned upon login: the user is asked for
- Xan email address (default is no email address); then a password should be
- Xprovided. If the user needs manager privileges, he has to provide both the
- Xmanager's email address and the system's password as they appear in the
- X\fIconfig\fP file. If he wishes owner privileges, he has to provide both
- Xhis email address as it appears in the \fIowners\fP file and his list's
- Xpassword as it appears in the \fIconfig\fP file. To gain subscriber privileges
- Xhe has to provide his email address as subscribed to the list where privileges
- Xare to be granted to, as well as the password \fIset\fP for that list.
- X.PP
- XA mismatch or no email address reduces privileges to a minimum. These
- Xare restricted to \fIhelp\fP, \fIinformation\fP, \fIrecipients\fP and
- X\fIstatistics\fP for nonprivate lists, \fIlists\fP, \fIindex\fP, \fIget\fP,
- X\fIview\fP, \fIrun\fP and \fIrelease\fP requests. Subscriber privileges extend
- Xthese to \fIset\fP, \fIrun\fP, \fIunsubscribe\fP and \fIwhich\fP requests.
- XOwners are granted permission to also issue \fIsystem\fP, \fIreports\fP,
- X\fIedit\fP, \fIput\fP, \fIapprove\fP and \fIdiscard\fP requests in
- Xaddition to the ones above. Finally, the \fImanager\fP may issue any
- Xrequest except \fIexecute\fP.
- X.PP
- XRequests for remote lists are serviced by attempting to connect to the
- Xremote servers serving these lists.
- X.PP
- XThe system may restrict connections to certain hosts, and/or reject connections
- Xfrom certain hosts. First, the system looks for the file \fIpriv.hosts\fP
- Xwhich lists hostnames and/or IP addresses that are allowed access; only
- Xhosts listed in this file are granted acces. For example, to allow access to
- Xhosts on one's local network only, one could do:
- X.sp
- X.ce
- Xln -s /etc/hosts HOMEDIR/priv.hosts
- X.sp
- XNext, the file \fIunwanted.hosts\fP is looked up, and connections from hosts
- Xlisted in it are rejected. Regular expressions may be used in both files.
- X.sp
- XThe duration of each connection is limited to the number of seconds
- Xgiven as argument to the -i flag. A maximum of 5 simultaneous connections
- Xcan be accepted at any time. All requests are serialized and the server may
- Xbe kept busy if it has not finished sending data to a socket (for example,
- Xwhen a user pipes the output he receives to more(1) and the amount of data
- Xto be sent is more than the the socket's buffer).
- X.PP
- XTo set up your system to accept such connections, the following line has to
- Xbe inserted into your host's /etc/services file:
- X.sp
- X.ce
- Xulistproc 372/tcp
- X.sp
- XThis port is privileged, therefore \fIserverd\fP has to be started with
- Xroot privileges (the \fIsetup\fP script takes care of this). If you do not
- Xhave root access you may choose any other port number above 1024, and in
- Xthis case \fIserverd\fP will give a warning every time it starts, which
- Xcan be ignored.
- X.PP
- XConsult the src/README file for qualification tests for your system to go
- Xinteractive and the Makefile for compilation options; also see the
- XPORT\ SPECIFIC section in \fIserver\fP(1). Lastly, the file HOMEDIR/welcome.live
- Xis copied upon log in, and it may be modified.
- X.PP
- XIf your setup uses a name server you may wish to link with libraries that
- Xprovide DNS support.
- X.SH SEE\ ALSO
- Xilp(1), list(1), listproc(1), queue(1), server(1)
- X.SH AUTHOR
- X.nf
- XAnastasios C. Kotsikonas
- XCopyright (c) 1991-93, Anastasios Kotsikonas
- XComments to tasos@cs.bu.edu
- X.fi
- *-*-END-of-doc/serverd.1-*-*
- echo x - doc/start.1
- sed 's/^X//' >doc/start.1 <<'*-*-END-of-doc/start.1-*-*'
- X.\" ListProcessor System
- X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
- X.\"
- X.TH start 1 "ListProcessor"
- X.SH NAME
- X\fBstart\fP \- start/stop the ListProcessor system
- X.SH SYNOPSIS
- X\fBstart\fP [\fB-c\fP] [\fB-r\fP] [\fB-k\fP]
- X.SH DESCRIPTION
- X\fIstart\fP is used to start or stop the ListProcessor system.
- XWhen starting the system, any
- Xprevious server processes still running are killed, all necessary
- Xlock files are created, any previous reports are archived into files with
- Xextension \fI.acc\fP, new files and directories are created for any
- Xnew mailing lists, and \fIserverd\fP(1) is spawned. \fIstart\fP reads the
- X\fIconfig\fP file (see \fIserver(1)\fP), and should always be run from the server
- Xaccount.
- X.SH OPTIONS
- XThe following command line options are recognized:
- X.TP
- X-c
- XSuppress confirmation when killing processes or when creating new
- Xmailing list directories and files.
- X.TP
- X-k
- XJust kill any old server system processes and exit.
- X.TP
- X-r
- XRestrict reporting to stdout.
- X.SH SEE\ ALSO
- Xserver(1), serverd(1)
- X.SH AUTHOR
- X.nf
- XAnastasios C. Kotsikonas
- XCopyright (c) 1991-93, Anastasios Kotsikonas
- XComments to tasos@cs.bu.edu
- X.fi
- *-*-END-of-doc/start.1-*-*
- echo x - doc/catmail.nr
- sed 's/^X//' >doc/catmail.nr <<'*-*-END-of-doc/catmail.nr-*-*'
- X
- X
- X
- Xcatmail(1) USER COMMANDS catmail(1)
- X
- X
- X
- XNNNNAAAAMMMMEEEE
- X ccccaaaattttmmmmaaaaiiiillll - append incoming mail to ListProcessor system files
- X
- XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
- X ccccaaaattttmmmmaaaaiiiillll {<----LLLL LLLLIIIISSSSTTTT____AAAALLLLIIIIAAAASSSS [----mmmm]> | <----rrrr>} [----ffff]
- X
- XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
- X _c_a_t_m_a_i_l is used to redirect incoming mail to the ListProces-
- X sor system to the appropriate files, according to the flags
- X specified. The files affected are HOMEDIR/requests (a repo-
- X sitory for requests), HOMEDIR/lists/*/mail (public messages
- X to be distributed) and HOMEDIR/lists/*/moderated (messages
- X to be screened out by a moderator). _c_a_t_m_a_i_l reports the user
- X id and user name that is currently executing it; the setuid
- X bit has to be set when installed. _c_a_t_m_a_i_l first locks the
- X output file before appending to it; if the file cannot be
- X locked after 3 minutes, the mail is saved under
- X HOMEDIR/lost+found or HOMEDIR/lists/*/lost+found; both _l_i_s_t
- X and _l_i_s_t_p_r_o_c lock their mail files while copying them to a
- X safe place. _c_a_t_m_a_i_l will time out after 2 minutes to avoid
- X deadlock situations, and the mail message may be returned to
- X the sender as undeliverable.
- X
- XOOOOPPPPTTTTIIIIOOOONNNNSSSS
- X The following command line options are recognized:
- X
- X -L LIST_ALIAS [-m]
- X If the -m flag is not specified, append to
- X HOMEDIR/lists/_L_I_S_T__A_L_I_A_S/mail; otherwise append to
- X HOMEDIR/lists/_L_I_S_T__A_L_I_A_S/moderated (see _l_i_s_t(_1)).
- X
- X -r Append to HOMEDIR/requests (overrides -L).
- X
- X -f Reformat the message in the process: all lines in the
- X message except the first starting with "From " are con-
- X verted to ">From ". (see also SYSTEM SETUP in
- X _s_e_r_v_e_r(1)).
- X
- XSSSSEEEEEEEE AAAALLLLSSSSOOOO
- X list(1), listproc(1), server(1)
- X
- XAAAAUUUUTTTTHHHHOOOORRRR
- X Anastasios C. Kotsikonas
- X Copyright (c) 1991-93, Anastasios Kotsikonas
- X Comments to tasos@cs.bu.edu
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- XAnastasios Kotsikonas 1
- X
- X
- X
- *-*-END-of-doc/catmail.nr-*-*
- echo x - doc/farch.nr
- sed 's/^X//' >doc/farch.nr <<'*-*-END-of-doc/farch.nr-*-*'
- X
- X
- X
- Xfarch(1) USER COMMANDS farch(1)
- X
- X
- X
- XNNNNAAAAMMMMEEEE
- X ffffaaaarrrrcccchhhh - archive files under the ListProcessor system
- X
- XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
- X ffffaaaarrrrcccchhhh {[----nnnn] [----bbbb | ----BBBB] [----ssss ssssiiiizzzzeeee] [----dddd ddddiiiirrrr] [----pppp ppppaaaasssssssswwwwoooorrrrdddd] [----
- X DDDD ddddeeeessssccccrrrriiiippppttttiiiioooonnnn] [----tttt ffffiiiilllleeee] [-u]} | {[----rrrr]} [----aaaa aaaarrrrcccchhhhiiiivvvveeee |||| ppppaaaatttthhhh----
- X ttttoooo----aaaarrrrcccchhhhiiiivvvveeee] [----ZZZZ] <ffffiiiilllleeeessss>
- X
- XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
- X _f_a_r_c_h is used to archive files under the ListProcessor sys-
- X tem or remove files already achived, with support provided
- X for private archives. Archives reside under
- X HOMEDIR/archives as subdirectories; the default is _l_i_s_t_p_r_o_c,
- X and it is also the master archive. Archives are hierarchi-
- X cally structured, and each archive has at least two files in
- X its directory:
- X
- X INDEX
- X A list of all subarchives including itself; the format
- X is one line per archive with the archive's name fol-
- X lowed by the archive's full path, followed by an
- X optional password:
- X
- X archive-name full-path-to-archive-directory [password]
- X
- X The first entry should be the archive itself; each
- X first level subarchive is listed next; then each second
- X level subarchive, starting with the first first-level-
- X archive's subarchives, followed by the second first-
- X level-archive's subarchives, etc. No sibling archives
- X may have the same name, although there is no such res-
- X triction for archives on different levels, or "cousin"
- X archives. The latter archives are distinguished by the
- X relative path needed to access them (see _s_e_r_v_e_r(1) for
- X more information).
- X
- X DIR A list of files available from that archive; the format
- X is one line per file with the file name followed by the
- X number of parts it may be split into, followed by the
- X number of bytes of each of the parts, followed by the
- X full path to the directory these parts can be found,
- X followed by a short descriptive message about the file
- X (optional). The descriptive message may span several
- X lines; each line (except the last) should end with a
- X '\':
- X
- X file nparts size-of-each-part+ full-path-to-directory [description [\]]
- X [multiple description lines [\]]*
- X
- X The number of parts the file is split into may be -1 to
- X indicate that this is a binary file.
- X
- X
- X
- X
- XKubota Computer 1
- X
- X
- X
- X
- X
- X
- Xfarch(1) USER COMMANDS farch(1)
- X
- X
- X
- X _f_a_r_c_h reports on the action taken on each input file:
- X whether it was split (and how many parts), whether it was
- X uuencoded, whether all files have been tar'red into a single
- X one, the archive this file was archived under, and the
- X directory the output file(s) (if any) has/have been placed.
- X It also reports when the input files are tarred.
- X
- XOOOOPPPPTTTTIIIIOOOONNNNSSSS
- X The following command line options are recognized:
- X
- X -n Do not split files when archiving them. The default is
- X to split them with each part not larger than the speci-
- X fied size (see the -s option below).
- X
- X -b Input files are binary; they are uuencoded before
- X archived.
- X
- X -B Input files are binary; they are neither uuencoded nor
- X split.
- X
- X -s size
- X Specify the maximum _s_i_z_e in kilobytes of each of the
- X subparts (default is 64).
- X
- X -d dir
- X Specify the _d_i_rectory that the output files are to be
- X placed; if left out, it defaults to the specified
- X archive's directory (HOMEDIR/archives/listproc if the
- X archive is left out as well). If the directory (and
- X all of its subdirectories, if any) does not exist, it
- X will be created.
- X
- X -p password
- X When a new archive is to be created, and that archive
- X is to be private, specify the access password.
- X
- X -D description
- X Put _d_e_s_c_r_i_p_t_i_o_n (most likely surrounded by single
- X quotes) in the DIR file as explanatory comment about
- X the archived file. This option does not make much sense
- X when archiving more than one file at the same time.
- X
- X -t file
- X Input files are tar'red into _f_i_l_e which is then
- X archived (the -b flag is automatically turned on).
- X Turning on the -B flag will prevent uuencoding of the
- X tar file. Note that whatever the path to _f_i_l_e may be,
- X it will be moved to the specified directory as speci-
- X fied by the -d flag.
- X
- X -u Update existing files while archiving; preserve the
- X current comment fields, unless -D is explicitly used.
- X
- X
- X
- XKubota Computer 2
- X
- X
- X
- X
- X
- X
- Xfarch(1) USER COMMANDS farch(1)
- X
- X
- X
- X -r Remove the specified file(s) from the specified archive
- X (see below), or the default one; it has higher priority
- X than all of the options above.
- X
- X -a archive | path-to-archive
- X Specify the _a_r_c_h_i_v_e that the input files will be
- X archived under (default is listproc). Archives on dif-
- X ferent levels of the hierarchy may have the same name
- X and in this case a _p_a_t_h-_t_o-_a_r_c_h_i_v_e may be specified to
- X distinguish between them; _p_a_t_h-_t_o-_a_r_c_h_i_v_e has the form
- X _a_r_c_h_i_v_e[/_a_r_c_h_i_v_e[/_a_r_c_h_i_v_e...]] (see also _s_e_r_v_e_r(_1)).
- X If any of the archives in the path do not exist, they
- X will be created with the necessary files.
- X
- X -Z Turn off file compression.
- X
- X File names in the DIR file have to be unique and _f_a_r_c_h will
- X not archive duplicate files.
- X
- XAAAARRRRCCCCHHHHIIIIVVVVIIIINNNNGGGG AAAA FFFFIIIILLLLEEEE
- X _f_a_r_c_h by default splits the input files if necessary (or the
- X tar file, if any), into files of maximum size as specified.
- X Each part will contain as many complete lines from the ori-
- X ginal input file as possible, without exceeding the speci-
- X fied size. Binary files (including the tar file) are uuen-
- X coded before they are archived unless the -B option is
- X specified, and all archived files are compressed, if possi-
- X ble.
- X
- XAAAADDDDDDDDIIIINNNNGGGG AAAA NNNNEEEEWWWW AAAARRRRCCCCHHHHIIIIVVVVEEEE
- X automatically
- X Simply specify the new archive as argument to the -a
- X flag. All necessary DIR and INDEX files as well as all
- X required directories will be created, and all parent
- X archives will be updated.
- X
- X by hand
- X Step 1
- X
- X Create a directory under HOMEDIR/archives or under an
- X existing archive's directory (beware of the hierarchy
- X structure), naming the directory after the archive.
- X The archive's name should be unique among its siblings
- X on that level in the hierarchy (besides, mkdir will not
- X let specify a name that already exists).
- X
- X Step 2
- X
- X Edit the master archive's index file
- X (HOMEDIR/archives/listproc/INDEX) and add the new
- X archive along with its path (and optional password --
- X see below) at the proper place in the file, making sure
- X
- X
- X
- XKubota Computer 3
- X
- X
- X
- X
- X
- X
- Xfarch(1) USER COMMANDS farch(1)
- X
- X
- X
- X you adhere to the rules about hierarchy outined above.
- X The first line of every INDEX file should be the
- X archive itself. Also edit (add to) every ancestor
- X archive's INDEX file, if the new archive is not the
- X default, again making sure you adhere to the same
- X rules.
- X
- X Step 3
- X
- X Create a new INDEX file in the new archive's directory
- X and put an entry for itself.
- X
- X Step 4
- X
- X Create an empty DIR file in the new archive's direc-
- X tory.
- X
- XPPPPRRRRIIIIVVVVAAAATTTTEEEE AAAARRRRCCCCHHHHIIIIVVVVEEEESSSS
- X Private archives are archives that require a password for
- X obtaining indices and/or files from them. To make an archive
- X private, simply append a password (case does not matter)
- X after its full path specification in every INDEX file the
- X archive is defined (its own plus all ancestors' -- the same
- X password has to be used in all of these files). Then, that
- X password has to be made known to all users who are to be
- X granted access to this archive. Note that all files in the
- X same private archive can be obtained with the same single
- X password.
- X
- XEEEEXXXXAAAAMMMMPPPPLLLLEEEESSSS
- X Archive src/data and src/data2 under archive listproc (the
- X default), using a maximum file size of 1K; the output
- X file(s) will be placed in /tmp/tmp:
- X
- X % farch -s 1 -d /tmp/tmp src/data src/data2
- X
- X Archive /etc/hosts under archive unix (that is
- X listproc/unix) -- the -n flag is used to avoid writing split
- X parts to /etc which is doomed to fail:
- X
- X % farch -n -a unix -d /etc -p private /etc/hosts
- X
- X Archive /etc/password under archive pub/unix (that is
- X listproc/pub/unix):
- X
- X % farch -n -a pub/unix -d /etc /etc/passwd
- X
- X Tar and archive all files in /usr/src to the default archive
- X and place the tar file under /tmp/tmp:
- X
- X % farch -t HOMEDIR/source -d /tmp/tmp /usr/src/*.c
- X
- X
- X
- X
- XKubota Computer 4
- X
- X
- X
- X
- X
- X
- Xfarch(1) USER COMMANDS farch(1)
- X
- X
- X
- X Descriptive messages about these files are added manually
- X into the archive's DIR file. However, the -D option can be
- X used to specify a string as follows:
- X
- X % farch -D 'ListProcessor system files' -t ulistproc.tar -n -d /usr/server /usr/server/*
- X
- XUUUUPPPPGGGGRRRRAAAADDDDIIIINNNNGGGG
- X If you are upgrading from:
- X
- X 5.5 The -B, -p, -r and -D options are new; functionality is
- X the same.
- X
- X 5.41 or less
- X Every DIR file should now include the size of each of
- X the parts of every file, placed between the number of
- X parts and the path name.
- X
- X The -a option has been extended to accept paths to
- X archives.
- X
- XRRRREEEESSSSTTTTRRRRIIIICCCCTTTTIIIIOOOONNNNSSSS
- X - Archive names and input files must use only lower case
- X characters of the alphabet.
- X
- XWWWWAAAARRRRNNNNIIIINNNNGGGGSSSS
- X - Input files that are to be tar'red should only include
- X relative path names; otherwise the end user may not be able
- X to extract them.
- X
- X - The tar file should not be any of the input files.
- X
- XSSSSEEEEEEEE AAAALLLLSSSSOOOO
- X server(1)
- X
- XAAAAUUUUTTTTHHHHOOOORRRR
- X Anastasios C. Kotsikonas
- X Copyright (c) 1991-93, Anastasios Kotsikonas
- X Comments to tasos@cs.bu.edu
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- XKubota Computer 5
- X
- X
- X
- *-*-END-of-doc/farch.nr-*-*
- echo x - doc/ilp.nr
- sed 's/^X//' >doc/ilp.nr <<'*-*-END-of-doc/ilp.nr-*-*'
- X
- X
- X
- Xilp(1) USER COMMANDS ilp(1)
- X
- X
- X
- XNNNNAAAAMMMMEEEE
- X iiiillllpppp - Interactive ListProcessor client
- X
- XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
- X iiiillllpppp [----vvvv] [----tttt ttttiiiimmmmeeeeoooouuuutttt] [----bbbb bbbbuuuuffffffffeeeerrrr----ssssiiiizzzzeeee iiiinnnn KKKK] hhhhoooosssstttt [ppppoooorrrrtttt]
- X
- XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
- X _i_l_p is a client that connects to the specified _h_o_s_t's
- X Interactive ListProcessor port (372) for a live session --
- X i.e. for processing requests live. Another _p_o_r_t may be
- X specified if necessary. The _h_o_s_t may be a host name, or an
- X IP address.
- X
- X Upon connection establishment, the protocol attempts to set
- X the user's privileges during the session by requesting an
- X email address and a password. These are used to determine
- X whether the user is to be granted system, owner, subscriber
- X or casual user privileges. If the user provides his owner
- X email address and his list's password, he will be granted
- X owner privileges. If he provides an email address that he
- X uses for subscription to a list, along with the password he
- X uses for that list, he will be granted subscriber
- X privileges. The system provides a brief listing of all valid
- X requests the user may issue during the session. If no email
- X address is provided, or no matches are found, the user is
- X restricted to a few requests.
- X
- X Requests for remote lists are serviced by attempting to con-
- X nect to the ILP server(s) (if any) of the system(s) that
- X handle those lists.
- X
- X The ILP server recognizes the following special requests:
- X
- X quit/exit
- X End the session.
- X
- X ?/privileges
- X Get a brief listing of all valid requests.
- X
- X timeleft
- X Prints the remaining time in seconds.
- X
- X &<new-line>
- X Input continues on the next line.
- X
- X binary
- X Switch to binary mode when transferring files.
- X
- X ascii
- X Switch to ASCII mode when transferring files.
- X
- X < filename
- X
- X
- X
- XKubota Computer 1
- X
- X
- X
- X
- X
- X
- Xilp(1) USER COMMANDS ilp(1)
- X
- X
- X
- X Input is taken from the specified file. Each line will
- X be interpreted as a separate request, unless the file
- X is specified in conjunction with a _p_u_t request. If the
- X '<' is to be used literally it must be escaped with '\'
- X or enclosed in quotes.
- X
- X > filename
- X Redirect the reply to the request to the specified
- X file. Error messages (such as rejections due to invalid
- X requests, etc.) are not redirected. When a file is
- X downloaded via a _g_e_t request, this will override the
- X file name that will be saved under. If the '>' is to be
- X used literally it must be escaped with \ or enclosed in
- X quotes.
- X
- X >> filename
- X Same as above, but the reply is appended to the speci-
- X fied file.
- X
- X | prog [args]
- X The output of the request is piped to _p_r_o_g; this is
- X similar to a UNIX pipe. _p_r_o_g may be any valid UNIX com-
- X mand, including other pipes, file redirections, etc.
- X Since '<' has higher precedence in this context, you
- X should escape any '<' characters intended to be used by
- X the pipe, otherwise the system will assume you are
- X feeding it batched requests. Quotes may also be used to
- X protect these characters.
- X
- XOOOOPPPPTTTTIIIIOOOONNNNSSSS
- X The following options are recognized:
- X
- X -v Turn verbose mode on; the server reply codes are echoed
- X along with predetermined messages.
- X
- X -t timeout
- X The default time out for a server response is 180
- X seconds; to reset use the -t flag. This timeout should
- X not be confused with the remaining time of a connec-
- X tion.
- X
- X -b buffer-size
- X The default socket buffer size is 8K; to reset use the
- X -b flag (the argument specifies kilobytes).
- X
- X
- XUUUUSSSSEEEERRRR PPPPRRRRIIIIVVVVIIIILLLLEEEEGGGGEEEESSSS
- X Casual users may only issue help, information, recipients
- X and statistics for nonprivate lists, lists, index, get,
- X view, search and release requests. Subscriber privileges
- X also include the set, run, unsubscribe and which requests.
- X Owners may, in addition, issue all of their administrative
- X
- X
- X
- XKubota Computer 2
- X
- X
- X
- X
- X
- X
- Xilp(1) USER COMMANDS ilp(1)
- X
- X
- X
- X requests.
- X
- X Issue a 'help live' request when you first connect to an ILP
- X server.
- X
- XRRRREEEESSSSTTTTRRRRIIIICCCCTTTTIIIIOOOONNNNSSSS
- X The connection duration is limited to a server-imposed
- X limit. After that, a connection may be broken by the server
- X as necessary. A connection will not be broken during a
- X transfer.
- X
- XEEEEXXXXAAAAMMMMPPPPLLLLEEEESSSS
- X request> put ermis ermis1 subscribers </usr/server/backup/lists/ERMIS/subs >out
- X
- X request> get listproc example.dat 1 3 >> out
- X
- X request> get listproc example.dat
- X
- X request> index ilp > ILP
- X
- X request> < /tmp/batched.requests
- X
- X request> index | more
- X
- X request> lists | cut -d ' ' -f1,2 | more
- X
- X request> search ilp "\>\> out"
- X
- X In this last example, we escape each > to protect it from
- X being interpreted as a regular expression separator, and
- X enclose the whole pattern in quotes to protect the \>\> from
- X being evaluated.
- X
- XFFFFIIIILLLLEEEESSSS
- X ilp.c, ilp.h
- X Source code for the client. See ilp.c for compile
- X options.
- X
- X ilpp.h
- X Definition of the Interactive ListProcessor Protocol.
- X
- X makefile
- X makefile to build _i_l_p. _i_l_p is written with BSD-style
- X signal handling, therefore on some hosts (like IBM AIX)
- X you will have to link with BSD versions of signal(2),
- X socket(3N), and fcntl(2). Platforms that have the
- X <sys/select.h> and <ulimit.h> header files should com-
- X pile with -DHAVE_SELECT_H and/or -DHAVE_ULIMIT_H. SCO
- X ports should compile with -Dsco. Always link with
- X libraries that provide DNS support (resolver linked
- X in).
- X
- X
- X
- X
- XKubota Computer 3
- X
- X
- X
- X
- X
- X
- Xilp(1) USER COMMANDS ilp(1)
- X
- X
- X
- XBBBBUUUUGGGGSSSS
- X Please report any bugs or enhancements to tasos@cs.bu.edu
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- XKubota Computer 4
- X
- X
- X
- *-*-END-of-doc/ilp.nr-*-*
- echo x - doc/list.nr
- sed 's/^X//' >doc/list.nr <<'*-*-END-of-doc/list.nr-*-*'
- X
- X
- X
- Xlist(1) USER COMMANDS list(1)
- X
- X
- X
- XNNNNAAAAMMMMEEEE
- X lllliiiisssstttt - process a specified ListProcessor mailing list
- X
- XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
- X lllliiiisssstttt ----LLLL <LLLLIIIISSSSTTTT____AAAALLLLIIIIAAAASSSS> [----1111] [----eeee] [----ssss] [----pppp] [----PPPP] [----mmmm ####] [----ffff]
- X [----rrrr] [----MMMM] [----dddd] [----iiii <aaaaddddddddrrrreeeessssssss>] [----vvvv] [----ZZZZ] [----DDDD]
- X
- XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN::::
- X _l_i_s_t distributes the message(s) sent to _l_i_s_t__a_l_i_a_s@_y_o_u_r-
- X _d_o_m_a_i_n; the file ".ignored" in the list's subdirectory is
- X used to filter out any unwanted messages (see below).
- X
- X Messages from mailer daemons are forwarded to the list's
- X owner and screened looking for delivery errors (in which
- X case appropriate action is taken -- users are either immedi-
- X ately removed from the list, or after a series of delivery
- X errors within a certain time frame -- entries removed from
- X the system's files are placed into
- X HOMEDIR/lists/*/removed.users and
- X HOMEDIR/lists/*/removed.alias files), whereas messages from
- X non-subscribers are returned to the original senders (the -f
- X flag overrides this). Messages whose first line looks like a
- X ListProcessor request are bounced back to the sender.
- X
- X Messages from news groups are distributed only to local sub-
- X scribers and peer lists. Messages from peers are distributed
- X to local subscribers and possibly posted to news groups.
- X Finally, messages from local subscribers are either distri-
- X buted locally, copies are sent to all peers, and are possi-
- X bly posted to news groups, or are forwarded to the list's
- X owner for screening if the list is moderated.
- X
- X All distributed messages (i.e. legitimate messages from sub-
- X scribers, peers and news groups -- not rejected, ignored or
- X error messages) are automatically archived in
- X HOMEDIR/lists/*/archive. In contrast, the files
- X HOMEDIR/lists/*/mbox contain all messages sent to these
- X lists (including, error, rejected and ignored messages).
- X
- X Email from one or more subscribers may be selectively dis-
- X tributed to an alternate list of recipients, by way of res-
- X tricted mail (see below), in which case mail will not be
- X distributed to the regular subscribers.
- X
- X When the system is for some reason aborted while making a
- X delivery, a built-in mechanism allows it to resume from the
- X point it left off.
- X
- XOOOOPPPPTTTTIIIIOOOONNNNSSSS
- X The following command line options are recognized:
- X
- X -L LIST_ALIAS
- X
- X
- X
- XKubota Computer 1
- X
- X
- X
- X
- X
- X
- Xlist(1) USER COMMANDS list(1)
- X
- X
- X
- X Process any messages sent to this _L_I_S_T__A_L_I_A_S --
- X _L_I_S_T__A_L_I_A_S should be in capital letters.
- X
- X -1 Execute only once; process the mailing list and return
- X control to _s_e_r_v_e_r_d(1); any new messages that may have
- X arrived in the meantime will be processed at a later
- X time. Without this option, _l_i_s_t will be listening for
- X messages for the specified list for ever. _s_e_r_v_e_r_d(1)
- X uses this option by default when spawning _l_i_s_t.
- X
- X -e Echo reports to the screen; it has no effect if the
- X system has been compiled with -DSYSLOG.
- X
- X -s By default, only subscribers can send messages to a
- X list. This option turns off subscription checking.
- X
- X -p By default, replies to messages posted to news groups
- X go to the list; this option forces replies to be for-
- X warded to the original author.
- X
- X -P By default, replies to messages sent to subscribers and
- X peers go to the list; this option forces replies to be
- X forwarded to the original author.
- X
- X -m number
- X Normally, each outgoing message has one recipient. This
- X flag switches to multi-recipient outgoing messages and
- X specifies the _n_u_m_b_e_r of recipients to be included in
- X these messages.
- X
- X -f Forward any messages from non-subscribers to the list's
- X owner. By default, they are returned to the sender.
- X
- X -r Restricted mail: _l_i_s_t will look at the ".restricted"
- X file (see below) to get the name of the alternate reci-
- X pients file. If the sender is listed in that ".res-
- X tricted" file, his messages will be distributed to
- X users listed in the alternate recipients file.
- X
- X -M The list is moderated; all incoming messages not from
- X the owner(s) are forwarded to the list's primary owner
- X for review and editing. The owner then sends back the
- X ones that are approved for posting (for an alternate
- X scheme see the MODERATED LISTS section below).
- X
- X -d Force a digest to be distributed. This flag is inter-
- X nally used by _s_e_r_v_e_r_d(1) when digest time has been
- X reached for this list.
- X
- X -i address
- X Send a partial digest to _a_d_d_r_e_s_s (what has accumulated
- X so far). This flag is internally used by _l_i_s_t_p_r_o_c(1)
- X
- X
- X
- XKubota Computer 2
- X
- X
- X
- X
- X
- X
- Xlist(1) USER COMMANDS list(1)
- X
- X
- X
- X when the user identified by _a_d_d_r_e_s_s changes his _m_a_i_l
- X mode from _d_i_g_e_s_t to something else. Note that when the
- X time arrives for the current digest to be distributed,
- X this user will get duplicate messages.
- X
- X -v Print version information.
- X
- X -Z Turn off file compression when archiving messages.
- X
- X -D Turns debugging on. When the _s_y_s_t_e_m mailmethod is used
- X (see _s_e_r_v_e_r(_1)), a copy of the last SMTP transaction
- X can be found in the files HOMEDIR/sent and
- X HOMEDIR/received.
- X
- XAAAADDDDDDDDIIIINNNNGGGG AAAA NNNNEEEEWWWW LLLLIIIISSSSTTTT
- X To add a new list, first shut the system down by executing
- X _s_t_a_r_t(1):
- X
- X % _s_t_a_r_t -_k
- X
- X Then edit the _c_o_n_f_i_g file and add a line defining the new
- X list -- you may wish to add a comment and/or disable a few
- X requests also. A new alias has to be set up in
- X /etc/aliases, /usr/lib/aliases or /usr/ucblib/aliases of the
- X following form:
- X
- X list_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f"
- X
- X If using surrogate mail, then the alias is defined as fol-
- X lows in /etc/mail/mailsurr:
- X
- X '.+' 'list_alias' '<S=0;F=1-255;C=*;HOMEDIR/catmail -L LIST_ALIAS -f'
- X
- X Note that _l_i_s_t__a_l_i_a_s is all lower case and _L_I_S_T__A_L_I_A_S is all
- X upper case. In this case _c_a_t_m_a_i_l(1) appends incoming mail to
- X the list's mail file (HOMEDIR/lists/LIST_ALIAS/mail). Also
- X keep in mind the case of reformatting messages as described
- X in _c_a_t_m_a_i_l(1).
- X
- X Finally, restart the system. At this point, the file
- X ".ignored" in the HOMEDIR/lists/LIST_ALIAS directory may be
- X edited to add more unwanted senders. You should also edit
- X the files ".welcome" and ".info" in the list's subdirectory;
- X the former is included in the return message for a new sub-
- X scription request for that list, and the latter is included
- X in the return message for an _i_n_f_o_r_m_a_t_i_o_n request for that
- X list (see _l_i_s_t_p_r_o_c(1)). These files may be simple text
- X files, or shell scripts (see the HELP section in _s_e_r_v_e_r(_1)).
- X
- XAAAADDDDDDDDIIIINNNNGGGG AAAA PPPPEEEEEEEERRRR LLLLIIIISSSSTTTT
- X Peer lists are mailing lists that happen to be subscribers
- X to one or more of your own mailing lists; they handle local
- X
- X
- X
- XKubota Computer 3
- X
- X
- X
- X
- X
- X
- Xlist(1) USER COMMANDS list(1)
- X
- X
- X
- X distribution of messages just like you do at your own site.
- X Peer lists can be mutual subscribers, so that a message ori-
- X ginating in a peer list gets distributed over there locally,
- X and a copy is sent to the other for local distribution, and
- X vice versa. An automatic mechanism is provided for avoiding
- X loops. A peer list can be added to a local mailing list by
- X using the script _p_e_e_r:
- X
- X peer <LIST_ALIAS> <remote alias> <peer address> <remote ListProcessor address>
- X
- X where _L_I_S_T__A_L_I_A_S is a local list alias in capital letters,
- X _r_e_m_o_t_e _a_l_i_a_s is the peer's alias on the remote machine,
- X _p_e_e_r _a_d_d_r_e_s_s is taken from the first line of the header of a
- X test message sent to your host by the peer (the first line
- X may be something like: "From peer@other-domain" -- see also
- X the discussion about aliases below), and
- X _r_e_m_o_t_e _L_i_s_t_P_r_o_c_e_s_s_o_r _a_d_d_r_e_s_s is the full email address of
- X the remote request-handler.
- X
- X Here is an example for establishing connection between two
- X peer lists a@domain1 and b@domain2: The _m_a_n_a_g_e_r at domain1
- X issues the following command:
- X
- X peer a b b@domain2 listproc@hdomain2
- X
- X The _m_a_n_a_g_e_r at domain2 issues the following command:
- X
- X peer b a a@domain1 listproc@domain1
- X
- X Once these two commands are issued the connection is
- X automatically set up. Peer lists should make sure that only
- X one of them posts to the same news group(s), and that only
- X one of them receives articles from the same news
- X group(s)/gateway(s). Lists handled by the same server can-
- X not be mutual peers. Finally, peer lists should not be regu-
- X lar subscribers (the _p_e_e_r script places them in a file
- X called ".peers").
- X
- XNNNNEEEEWWWWSSSS GGGGRRRROOOOUUUUPPPPSSSS AAAANNNNDDDD GGGGAAAATTTTEEEEWWWWAAAAYYYYSSSS
- X A mailing list may be linked with one or more news groups
- X (or gateways) from which it may receive messages for local
- X distribution, and/or send messages to the newsgroup(s) for
- X posting -- in this case only messages from regular sub-
- X scribers and peers are sent for posting, i.e. no news mes-
- X sages will be posted to any news groups (or gateways). A
- X news group or gateway is linked using the script _n_e_w_s:
- X
- X news <LIST_ALIAS> <news group> <email address> <mode>
- X
- X where _L_I_S_T__A_L_I_A_S is a local list alias (in capital letters)
- X that is being linked to the news group, _n_e_w_s _g_r_o_u_p is the
- X name of the news group (used only when posting) e.g.
- X
- X
- X
- XKubota Computer 4
- X
- X
- X
- X
- X
- X
- Xlist(1) USER COMMANDS list(1)
- X
- X
- X
- X misc.test, _e_m_a_i_l _a_d_d_r_e_s_s is the address of the backbone or
- X moderator of the news group, or the gateway, and it is taken
- X from the first line of the header of a test message sent to
- X your host by the group (the first line may be something
- X like: "From gateway@foo ..." -- see also the discussion
- X about aliases below); _m_o_d_e is one of the following:
- X
- X receive
- X The list will only be receiving messages from this news
- X group and never post to it. This allows access to the
- X group (or gateway) to send articles to the list.
- X
- X send_receive
- X The list may be receiving messages from this news
- X group, and it will post to it any messages from regular
- X subscribers and peer lists (messages from news groups
- X are never posted to other news groups). This also
- X allows access to the group (or gateway) to send arti-
- X cles to the list.
- X
- X Of course, the news group's caretaker has to be notified of
- X the list's address so that articles will indeed be sent to
- X it. Finally, news groups should not be regular subscribers
- X (the _n_e_w_s script places them in a file called ".news").
- X
- X If the config option _p_o_s_t__m_a_i_l is used, the system will use
- X _i_n_e_w_s for posting, and it assumes that the path to it is
- X /usr/lib/news/inews, so make sure that _i_n_e_w_s resides there,
- X or a link exists to it. In this case, the group's name is
- X used for posting (e.g. misc.test). If instead _g_a_t_e__m_a_i_l is
- X defined, messages will be sent via email to news gateways
- X (using the _e_m_a_i_l _a_d_d_r_e_s_s) -- the _n_e_w_s _g_r_o_u_p name has no sig-
- X nificance in this case.
- X
- XMMMMOOOODDDDEEEERRRRAAAATTTTEEEEDDDD LLLLIIIISSSSTTTTSSSS
- X The system supports two schemes for moderating lists. The
- X first scheme uses the -M flag to _l_i_s_t(1), and in this case
- X messages not from the list's owner(s) are forwarded to the
- X list's primary owner for review; the owner then sends back
- X the approved (and possibly edited) ones.
- X
- X The second scheme uses the -m flag to _c_a_t_m_a_i_l(1). In this
- X case, the list's alias is changed slightly in the aliases
- X file:
- X
- X list_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f -m"
- X
- X and similarly if using surrogate mail. _l_i_s_t(1) distributes
- X messages from a file called _m_a_i_l; by having incoming mes-
- X sages redirected to the file _m_o_d_e_r_a_t_e_d (the effect of the -m
- X flag to _c_a_t_m_a_i_l(1)), the list's owner may _a_p_p_r_o_v_e or _d_i_s_c_a_r_d
- X any number of these messages (see _l_i_s_t_p_r_o_c(1)). Whenever a
- X
- X
- X
- XKubota Computer 5
- X
- X
- X
- X
- X
- X
- Xlist(1) USER COMMANDS list(1)
- X
- X
- X
- X new mail message arrives for a moderated list, a copy is
- X sent to the list's owner with instructions for approving or
- X discarding it. These instructions include a unique tag
- X number for identifying that message. When a message is
- X approved, it is transferred to the _m_a_i_l file for later
- X delivery, and when discarded, it is simply removed from the
- X _m_o_d_e_r_a_t_e_d file. This scheme cuts down on mail traffic.
- X
- XRRRREEEESSSSTTTTRRRRIIIICCCCTTTTEEEEDDDD MMMMAAAAIIIILLLL
- X When the -r flag is used with _l_i_s_t(1), for every message
- X received its sender is checked against a list of "res-
- X tricted" email addresses, in the file ".restricted" in the
- X list's directory -- a subset of the ".subscribers" file. If
- X a match is found, mail is forwarded to the people listed in
- X the file following this email address. If no match is found,
- X the message is distributed to the regular subscribers. Note
- X that the alternate recipients file should be in the same
- X format as the ".subscribers".
- X
- X....SSSSUUUUBBBBSSSSCCCCRRRRIIIIBBBBEEEERRRRSSSS
- X The format is as follows:
- X
- X One entry per line; each entry is the full email address of
- X the subscriber as it appears in the "From " field, followed
- X by the word "ACK" (in which case his/her message will be
- X sent back to him/her as an acknowledgement), "NOACK" (the
- X opposite), "POSTPONE" (no mail will be sent until the user
- X changes mode again), or "DIGEST" (digests are periodically
- X sent), followed by a string that plays the role of the
- X user's password, followed by either "YES" or "NO" which are
- X the values of the conceal attribute, followed by the
- X subscriber's name. See also _l_i_s_t_p_r_o_c(1).
- X
- X....RRRREEEESSSSTTTTRRRRIIIICCCCTTTTEEEEDDDD
- X The format is as follows:
- X
- X One entry per line; each entry is the full email address of
- X the subscriber, followed by a file name where email
- X addresses of recipients are listed (just like in the ".sub-
- X scribers" file). Example:
- X
- X jdoe@foo.bar.com HOMEDIR/lists/LIST_ALIAS/.recipients
- X
- X If the recipient file given is the word "NONE", then no one
- X will receive any messages.
- X
- X....AAAALLLLIIIIAAAASSSSEEEESSSS
- X It is possible that a subscriber's/peer's/news
- X group's/gateway's email may arrive using a different path
- X than registered, which may raise subscription issues. To
- X work around this, each list provides a ".aliases" file in
- X its subdirectory, which may contain alternate email
- X
- X
- X
- XKubota Computer 6
- X
- X
- X
- X
- X
- X
- Xlist(1) USER COMMANDS list(1)
- X
- X
- X
- X addresses to be used when checking for subscription. The
- X format is one line per alias with the following information:
- X
- X alias-address address-as-subscribed
- X
- X Please note that only the subscribed address is used for
- X sending out email (see next section about regular expres-
- X sions).
- X
- X The aliased address may be a regular expression with
- X egrep(1) style syntax, in which case the following charac-
- X ters have special meanings: '~', if leading the regular
- X expression it reverses its meaning; '|' and '&' separate
- X multiple regular expressions (logical OR and AND); '<' '>'
- X group regular expressions (we preserve the meaning of the
- X parentheses from ed(1), and remove the meaning of < and >
- X from ed(1) since in the ListProcessor context they are
- X either the default, or inappropriate). These can be used
- X literally by escaping them with '\'. In addition, the fol-
- X lowing characters should be defined in matched pairs: (),
- X <>, [], "". For example:
- X
- X jdoe@.*\.bar\.com jdoe@foo.bar.com
- X
- X will enable this user to send messages from any machine in
- X his local network and receive replies at foo.bar.com -- keep
- X in mind that a '.' matches exactly one character, and '.*'
- X matches zero or more characters. In a more complicated
- X example:
- X
- X ~jdoe@cc.*|jdoe@....*\.bar\.com jdoe@foo.bar.com
- X
- X will match if jdoe sends a message from a machine whose name
- X does not start with 'cc', or from a machine whose name has
- X at least 3 characters.
- X
- X If certain parts of the regular expression are
- X parenthesized, then the strings that matched the subexpres-
- X sions can be used in the 'address-as-subscribed' to form new
- X return addresses; these matched strings are accessed by \_n
- X where _n is a digit between 1 and 9. For example, if the
- X sender is:
- X
- X GATE!HOP!USER@UUCP.SOME.COM
- X
- X and the entry in the ".aliases" file reads:
- X
- X [^!@]*!([^!@.]*)!([^!@]*)@.* \2@\1.UUCP
- X
- X then what will be returned as 'address-as-subscribed' is:
- X
- X USER@HOP.UUCP
- X
- X
- X
- XKubota Computer 7
- X
- X
- X
- X
- X
- X
- Xlist(1) USER COMMANDS list(1)
- X
- X
- X
- X This way you can map addresses coming in via various gate-
- X ways to steady ones (\2 refers to the second set of
- X parentheses, and \1 to the first). Managers may edit
- X HOMEDIR/src/regex.c to test regular expression behavior,
- X introduce ls(1) style meanings to the * and ? wild charac-
- X ters, undefine ed(1) special characters, and enforce strict
- X egrep(1) syntax (remove the meanings of ~ & < and >).
- X
- X Regular expressions should be used with caution for obvious
- X reasons.
- X
- X If someone is experiencing subscription problems, you may
- X wish to add their alternate email address(es) in this file.
- X This includes regular subscribers, news groups, peers and
- X gateways. If the sender is also a restricted subscriber, do
- X not forget to put another entry in ".restricted" with the
- X new alternate address. Any number of aliases may be defined
- X for each individual address.
- X
- X In addition, a ".aliases" file is also provided for ListPro-
- X cessor requests and is under HOMEDIR. The same syntax is
- X used, but each entry has a slightly different meaning:
- X
- X address-as-arrived address-used-for-reply
- X
- X In this case, _a_d_d_r_e_s_s-_u_s_e_d-_f_o_r-_r_e_p_l_y will be used to reply
- X to all requests sent in by _a_d_d_r_e_s_s-_a_s-_a_r_r_i_v_e_d. A user may
- X have any number of aliases, but only the first one matching
- X _a_d_d_r_e_s_s-_a_s-_a_r_r_i_v_e_d will be used. Like before, the first
- X argument may be a regular expression and the second may use
- X the matches in the first.
- X
- X For each new list, the system puts the following default
- X alias in its ".aliases" file:
- X
- X ^@.*:(.*)@(.*\..*) \1@\2
- X
- X This removes source routing.
- X
- X....IIIIGGGGNNNNOOOORRRREEEEDDDD
- X As described before, the system's home directory as well as
- X every list's subdirectory contains a ".ignored" file which
- X is used to filter out messages sent by certain users. The
- X default file contains entries for server, bin, and sys; you
- X may wish to add an entry for every list alias that is
- X defined on your system. A list's ".ignored" file also con-
- X tains an entry of its alias and full email address, as well
- X as the server account's full email address.
- X
- X Entries in this file may also be regular expressions as
- X explained in the previous section. For example, to restrict
- X requests (and postings) to .com and .edu domain addresses,
- X
- X
- X
- XKubota Computer 8
- X
- X
- X
- X
- X
- X
- Xlist(1) USER COMMANDS list(1)
- X
- X
- X
- X one may add:
- X
- X ~<.*\.com|.*\.edu>
- X
- X Notice, it is incorrect to list them as follows:
- X
- X ~.*\.com
- X ~.*\.edu
- X
- X as anything not from the .com domain matches the first regu-
- X lar expression, and therefore will be ignored. To refuse
- X access to certain user names and certain sites one may
- X include:
- X
- X .*\.bar\.com|jdoe@.*
- X
- X The system's manager should use extra caution when adding
- X regular expressions to the system's ".ignored" file, because
- X a simple '.*' prohibits anyone from using its services.
- X
- XSSSSEEEEEEEE AAAALLLLSSSSOOOO
- X catmail(1), listproc(1), server(1), serverd(1), start(1)
- X
- XAAAAUUUUTTTTHHHHOOOORRRR
- X Anastasios C. Kotsikonas
- X Copyright (c) 1991-93, Anastasios Kotsikonas
- X Comments to tasos@cs.bu.edu
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- XKubota Computer 9
- X
- X
- X
- *-*-END-of-doc/list.nr-*-*
- echo x - doc/listproc.nr
- sed 's/^X//' >doc/listproc.nr <<'*-*-END-of-doc/listproc.nr-*-*'
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- XNNNNAAAAMMMMEEEE
- X lllliiiissssttttpppprrrroooocccc - process requests sent to the ListProcessor
- X request handler
- X
- XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
- X lllliiiissssttttpppprrrroooocccc [----1111] [----eeee] [----iiii] [----nnnn] {[----aaaa <LLLLIIIISSSSTTTT____AAAALLLLIIIIAAAASSSS>]}* {[----
- X rrrr <rrrreeeeqqqq>]}* {[----dddd <rrrreeeeqqqq>]}* {[----bbbb <rrrreeeeqqqq>]}* [----BBBB] [----DDDD]
- X
- XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
- X _l_i_s_t_p_r_o_c processes user requests sent to _l_i_s_t_p_r_o_c@_y_o_u_r-
- X _d_o_m_a_i_n, forwards requests about known remote lists, and
- X processes list-owner administrative requests (see also the
- X LIST OWNERS section below). Each request should appear in a
- X separate line with any possible arguments. The file
- X ".ignored" is used in the system's home directory to filter
- X out unwanted senders. If the system is not instructed to
- X ignore invalid requests (see the CONFIG section in
- X _s_e_r_v_e_r(_1)), the sender is notified of the first invalid
- X request; all subsequent requests are ignored. For each suc-
- X cessfully completed request, a confirmation is sent back to
- X the sender.
- X
- X _l_i_s_t_p_r_o_c stops reading requests when it encounters the
- X string "--" in a line by itself, which on most systems sig-
- X nifies the start of the .signature message, or at the first
- X occurence of a thankful request. _l_i_s_t_p_r_o_c reads the _c_o_n_f_i_g
- X file (see _s_e_r_v_e_r(_1)).
- X
- X Subscriptions may be manager-approved (private lists), files
- X and archive indices may be password protected (private
- X archives), and requests may be placed in a batch queue. A
- X single request may span multiple lines if each part ends
- X with &\_n.
- X
- XUUUUSSSSEEEERRRR RRRREEEEQQQQUUUUEEEESSSSTTTTSSSS
- X The following user requests are recognized (requests may be
- X abbreviated):
- X
- X _h_e_l_p [topic]
- X Send a help message on all valid requests or the
- X selected topic (possibly a request) only.
- X
- X _s_e_t list [option arg(s)]
- X Without the optional arguments, return the current
- X values for all options set for _l_i_s_t; otherwise, set
- X subscriber preferences for _l_i_s_t.
- X
- X _o_p_t_i_o_n can be:
- X
- X _m_a_i_l: set mail preferences.
- X
- X _a_r_g has to be one of the following:
- X
- X
- X
- XAnastasios Kotsikonas 1
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X _a_c_k: send a copy of the current message to the
- X original sender.
- X
- X _n_o_a_c_k: do not send a copy of the current message
- X to the original sender. This is the default for
- X newly subscribed users.
- X
- X _p_o_s_t_p_o_n_e: do not send any messages to the partic-
- X ular subscriber until he changes status again.
- X
- X _d_i_g_e_s_t: do not send individual messages to the
- X particular subscriber. Instead, store messages in
- X a digest and send it when the digest exceeds a
- X specified number of lines, or when a specified
- X amount of time has passed since the last digest
- X was sent.
- X
- X If the mail mode is changed from _d_i_g_e_s_t to any-
- X thing else, all messages currently stored for the
- X next digest will be sent to the subscriber at
- X once, in digest format.
- X
- X _p_a_s_s_w_o_r_d: change the password (used to establish sub-
- X scriber privileges when connecting to ListProcessor
- X for a "live" session and for the option below).
- X
- X _a_r_g_s must be: old-password new-password.
- X
- X _a_d_d_r_e_s_s: set the address the user is subscribed with
- X (if allowed for this list).
- X
- X _a_r_g_s must be: current-password new-address.
- X
- X _c_o_n_c_e_a_l: set the user's visibility.
- X
- X _a_r_g must be one of the following:
- X
- X _y_e_s: the user is not listed in _r_e_c_i_p_i_e_n_t_s and
- X _s_t_a_t_i_s_t_i_c_s requests.
- X
- X _n_o: the user's email address and name are made
- X public.
- X
- X _s_u_b_s_c_r_i_b_e list full_name
- X Subscribe the sender to _l_i_s_t (note, his email address
- X is used for subscription, not his _f_u_l_l__n_a_m_e). A pass-
- X word is assigned by the system at that time and is
- X included in the reply message to the new subscriber.
- X The password is to be used when connecting to the
- X interactive part of the system for identification pur-
- X poses, and for changing the subscription address if
- X allowed for this list.
- X
- X
- X
- XAnastasios Kotsikonas 2
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X _w_h_i_c_h
- X Get a list of local mailing lists to which the sender
- X has subscribed.
- X
- X _u_n_s_u_b_s_c_r_i_b_e list
- X Remove the sender from the specified _l_i_s_t.
- X
- X _s_i_g_n_o_f_f list
- X Alias of the unsubscribe request.
- X
- X _r_e_c_i_p_i_e_n_t_s list
- X Get a list of all subscribers of _l_i_s_t. The request is
- X also forwarded to all peer lists, and the servers han-
- X dling them will respond accordingly. The user is noti-
- X fied when this request is being forwarded. If a list is
- X private, only members may issue this request.
- X
- X _r_e_v_i_e_w list
- X Alias of the recipients request.
- X
- X _i_n_f_o_r_m_a_t_i_o_n list
- X Get information about a particular _l_i_s_t.
- X
- X _s_t_a_t_i_s_t_i_c_s list {[subscriber email address(es)] | [-all]}
- X Obtain a count of messages sent per subscriber to the
- X specified _l_i_s_t, or by those subscribers given as argu-
- X ment only (wild characters are supported). If -_a_l_l is
- X specified, then statistics are compiled for all users
- X (currently subscribed or not) who have posted to the
- X list in the past. The request is also forwarded to all
- X peer lists and the servers handling them will respond
- X accordingly. The user is notified when this request is
- X being forwarded. If a list is private, only members
- X may issue this request.
- X
- X _r_u_n list [password cmd [args]]
- X Without the optional arguments, just list all commands
- X that may be executed by subscribers of this _l_i_s_t. Oth-
- X erwise, run _c_m_d with the optional _a_r_g_s, if the correct
- X _p_a_s_s_w_o_r_d is provided. The reply will contain the output
- X from stdout and/or stderr.
- X
- X _l_i_s_t_s
- X Obtain a list of mailing list addresses that are ser-
- X viced by this system, with a small description of their
- X purpose. If remote lists (see below) are also defined,
- X their addresses and descriptive messages will also be
- X included.
- X
- X _i_n_d_e_x [archive | path-to-archive] [/password] [-all]
- X Obtain an index of files in the specified _a_r_c_h_i_v_e (or
- X the master archive if none specified) and all of its
- X
- X
- X
- XAnastasios Kotsikonas 3
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X subarchives if the the -_a_l_l option is specified. Cer-
- X tain archives may be private, and these require a
- X /_p_a_s_s_w_o_r_d to be able to obtain their indices. Archives
- X on different places in the hierarchy may have the same
- X names and they can be distinguished by specifying paths
- X to them; _p_a_t_h-_t_o-_a_r_c_h_i_v_e has the form
- X _a_r_c_h_i_v_e[/_a_r_c_h_i_v_e[/_a_r_c_h_i_v_e...]]. _i_n_d_e_x requests always
- X report the paths to the archives they list.
- X
- X _g_e_t <archive | path-to-archive> file [/password] [parts]
- X Get the specified _f_i_l_e from the _a_r_c_h_i_v_e given. The file
- X may have been split into smaller parts due to its size,
- X in which case each part will be sent in a different
- X email message. If only certain _p_a_r_t_s are desired, they
- X may be given as arguments (numbers, separated by spaces
- X -- ranges are not recognized). Certain archives may be
- X private, in which case their /_p_a_s_s_w_o_r_d has to be pro-
- X vided in order to get the desired files. Archives on
- X different places in the hierarchy may have the same
- X names and they can be distinguished by specifying paths
- X to them; _p_a_t_h-_t_o-_a_r_c_h_i_v_e has the form
- X _a_r_c_h_i_v_e[/_a_r_c_h_i_v_e[/_a_r_c_h_i_v_e...]]. If the file is pure
- X binary, it will be uuencoded first.
- X
- X _s_e_a_r_c_h <archive | path-to-archive> [/password] [-all] <pat-
- X tern>
- X Search all files in the specified archive (and all of
- X its subarchives if -_a_l_l) and return lines that match
- X the _p_a_t_t_e_r_n. The pattern can be an extended regular
- X expression with egrep(1)-style syntax, with support for
- X the following additional operators: '~', if leading the
- X regular expression it reverses its meaning; '|' and '&'
- X separate multiple regular expressions (logical OR and
- X AND); '<' '>' group regular expressions (we preserve
- X the meaning of the parentheses from ed(1), and remove
- X the meaning of < and > from ed(1) since in the ListPro-
- X cessor context they are either the default, or inap-
- X propriate). These can be used literally by escaping
- X them with '\'. In addition, the following characters
- X should be defined in matched pairs: (), <>, []. _p_a_t_t_e_r_n
- X may be enclosed in single or double quotes. Pattern
- X matching is case insensitive.
- X
- X _f_a_x <fax-no> <archive | path-to-archive> file [/password]
- X [parts]
- X Same as the _g_e_t request except that the files are faxed
- X to the specified number.
- X
- X _r_e_l_e_a_s_e
- X Get information about the current release of this
- X server system.
- X
- X
- X
- X
- XAnastasios Kotsikonas 4
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X _e_x_e_c_u_t_e password #command [arguments]
- X Intended for the system's _m_a_n_a_g_e_r, this will execute
- X the _c_o_m_m_a_n_d with the optional _a_r_g_u_m_e_n_t_s and send the
- X output (if any) from stdout and/or stderr to the
- X sender. See the sample _c_o_n_f_i_g file for _p_a_s_s_w_o_r_d defini-
- X tion.
- X
- X For a list of the list administration requests that may be
- X issued by list owners, see the LIST OWNERS section below.
- X
- XOOOOPPPPTTTTIIIIOOOONNNNSSSS
- X The following command line options are recognized:
- X
- X -1 Execute only once; process any requests and return con-
- X trol to _s_e_r_v_e_r_d(1); any new messages that may have
- X arrived in the meantime will be processed at a later
- X time. Without this option, _l_i_s_t_p_r_o_c will be listening
- X for requests for ever. _s_e_r_v_e_r_d(1) uses this option by
- X default when spawning _l_i_s_t_e_r_v.
- X
- X -e Echo reports to the screen; it has no effect if the
- X system has been compiled with -DSYSLOG.
- X
- X -i Go to interactive mode -- messages by _l_i_s_t_p_r_o_c are not
- X mailed out but instead _s_e_r_v_e_r_d(1) reads them during its
- X interactive session. Do not use this option in the _c_o_n_-
- X _f_i_g file (see _s_e_r_v_e_r(_1)).
- X
- X -n By default, peer servers are notified upon _s_t_a_t_i_s_t_i_c_s
- X and _r_e_c_i_p_i_e_n_t_s requests. The system uses a protocol for
- X avoiding loops as described in _s_e_r_v_e_r(1). If you
- X detect loops with other servers, you should use this
- X option to turn off notification of peer servers.
- X
- X -a LIST_ALIAS
- X Usually, subscriptions are automatic. This option turns
- X off automatic subscription to the specified list
- X (_L_I_S_T__A_L_I_A_S should be in capital letters), and makes
- X this list private (members only may issue _r_e_c_i_p_i_e_n_t_s
- X and _s_t_a_t_i_s_t_i_c_s requests). The sender is notified of
- X this effect, and a message is sent to the list's owner
- X requesting his/her approval, with instructions for
- X placing the subscription. Notice that the specified
- X list has to be defined beforehand via a _l_i_s_t directive
- X in the _c_o_n_f_i_g file. This option may be repeated any
- X number of times.
- X
- X -c LIST_ALIAS
- X Conceal _L_I_S_T__A_L_I_A_S from _l_i_s_t_s requests.
- X
- X -r request
- X Place a restriction on the specified server _r_e_q_u_e_s_t as
- X
- X
- X
- XAnastasios Kotsikonas 5
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X outlined above. If the number of users on the system
- X at the time the request is about to be processed is
- X above the limit given in the _c_o_n_f_i_g file (using the
- X _r_e_s_t_r_i_c_t_i_o_n directive), the request is rejected --
- X meant for requests that may take a considerable amount
- X of resources such as the _s_t_a_t_i_s_t_i_c_s request -- this
- X option may be repeated any number of times. List
- X administration requests are not subject to these res-
- X trictions (see later on).
- X
- X -d request
- X Disable _r_e_q_u_e_s_t, i.e. make it totally unknown to the
- X server -- this supersedes any _d_i_s_a_b_l_e directives for
- X this request in the _c_o_n_f_i_g file, i.e. this request will
- X not be recognized for any list (see _s_e_r_v_e_r(1)). How-
- X ever, help is still available for that request. List
- X administration requests are also subject to these res-
- X trictions (see later on). This option may be repeated
- X any number of times.
- X
- X -b request
- X All such _r_e_q_u_e_s_ts will be batch-processed if they
- X arrive between the hours specified in the _c_o_n_f_i_g file.
- X This option may be repeated any number of times.
- X
- X -B Process the batch queue. This is done automatically by
- X _s_e_r_v_e_r_d(1) after midnight every day, or when the system
- X is restarted, so no further action needs to be taken.
- X Caution: do not place this option in the definition of
- X _s_e_r_v_e_r in the _c_o_n_f_i_g file. If you do so, only the batch
- X queue will be processed (no new requests will be pro-
- X cessed, ever). The batch queue is processed once a day
- X only, unless the system is restarted repeatedly.
- X
- X -D Turns debugging on. When the _s_y_s_t_e_m mailmethod is used,
- X a copy of the last SMTP transaction can be found in the
- X files HOMEDIR/sent and HOMEDIR/received.
- X
- XPPPPEEEEEEEERRRR SSSSEEEERRRRVVVVEEEERRRRSSSS
- X The system supports the notion of remote lists. A ListPro-
- X cessor may know of remote lists served by remote servers.
- X Yet users may send requests about these remote lists to this
- X server, which will in turn forward them to the remote
- X servers. The user is notified when a list is not local and
- X his/her request is about to be forwarded. A _l_i_s_t_s request
- X will tell the user which remote lists are known to this
- X server.
- X
- X Remote lists should be made known to this server only if
- X they are served by a server of version 5.31 or higher. This
- X restriction is posed because of incompatible requests across
- X various list management systems. See the discussion about
- X
- X
- X
- XAnastasios Kotsikonas 6
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X the _c_o_n_f_i_g file for setting up remote lists.
- X
- X In addition, _r_e_c_i_p_i_e_n_t_s and _s_t_a_t_i_s_t_i_c_s requests are for-
- X warded to the servers handling peer lists (the -n flag to
- X _l_i_s_t_p_r_o_c turns this feature off).
- X
- XLLLLIIIISSSSTTTT OOOOWWWWNNNNEEEERRRRSSSS
- X List owners are individuals responsible for list administra-
- X tion via mail requests. Thus, list owners may be remotely
- X located. Each list has to have at least one list owner.
- X These owners may be different than the system's _m_a_n_a_g_e_r, and
- X have special privileges: they may issue requests on users'
- X behalf (add a user, remove a user, etc.) overriding system
- X restrictions set on regular users (these include disabled
- X commands as described above), obtain reports about the lists
- X they administer, append to the ".aliases" and ".ignored"
- X files, change the welcoming (".welcome") and informative
- X (".info") messages, as well as other system files such as
- X the aliases file (".aliases"), the ".ignored" file, the sub-
- X scribers file (".subscribers"), the news file (".news") and
- X the peers file (".peers"). In addition, they may moderate
- X their lists and they receive various error messages pertain-
- X ing to their lists. All administrative requests are author
- X authenticated and password protected. Whenever a message
- X cannot be author authenticated, the list's owner and _m_a_n_a_g_e_r
- X are notified.
- X
- X On the other hand, list owners may not add restricted users;
- X this service can be provided by contacting the system's
- X _m_a_n_a_g_e_r.
- X
- X List owners may also receive copies of user requests and/or
- X error messages such as invalid postings, syntax errors on
- X requests, etc. These options are described in the following
- X sections.
- X
- X Defining list owners
- X Once a new mailing list is defined in the _c_o_n_f_i_g file,
- X the list's owner address and access password are pro-
- X vided to the _l_i_s_t directive. Of course, this password
- X should be made known to the owner; it will be needed
- X for all administrative requests. Next, the owner's
- X address has to be registered in HOMEDIR/owners; the
- X _m_a_n_a_g_e_r simply edits this file adding the owner's
- X address along with the list's name (alias) he is
- X assigned to, followed by any preferences (see below).
- X Multiple owners for a list may be defined by adding
- X their addresses to this file, and providing them with
- X the list's password. However, only the primary owner's
- X address (as defined by the _l_i_s_t directive) will be used
- X as reference in correspondence and for system-error
- X notifications, and only the primary owner will be
- X
- X
- X
- XAnastasios Kotsikonas 7
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X forwarded messages from his moderated list for appro-
- X val. The _m_a_n_a_g_e_r should also add his address (login
- X name) to this file.
- X
- X Owner preferences
- X The primary owner may wish to be copied on certain
- X replies to user requests (such as subscribe), on error
- X conditions (rejected postings, invalid requests, etc.),
- X or on all cases. These preferences are listed in the
- X _o_w_n_e_r_s file on the line his address and list are
- X defined. Valid preferences are:
- X
- X CCSET: copy on _s_e_t requests.
- X
- X CCSUBSCRIBE: copy on _s_u_b_s_c_r_i_b_e requests.
- X
- X CCUNSUBSCRIBE: copy on _u_n_s_u_b_s_c_r_i_b_e requests.
- X
- X CCRECIPIENTS: copy on _r_e_c_i_p_i_e_n_t_s requests.
- X
- X CCINFORMATION: copy on _i_n_f_o_r_m_a_t_i_o_n requests.
- X
- X CCSTATISTICS: copy on _s_t_a_t_i_s_t_i_c_s requests.
- X
- X CCRUN: copy on _r_u_n requests.
- X
- X CCPRIVATE: copy on requests rejected because they are
- X open only to the list's members.
- X
- X CCERRORS: copy on various error conditions.
- X
- X CCALL: all of the above.
- X
- X Owner preferences are optional.
- X
- X The _m_a_n_a_g_e_r may define preferences for himself as well by
- X using the keyword _s_e_r_v_e_r in place of a list alias. However,
- X such preferences make sense only in the following cases:
- X
- X CCGET: copy on _g_e_t requests.
- X
- X CCINDEX: copy on _i_n_d_e_x requests.
- X
- X CCLISTS: copy on _l_i_s_t_s requests.
- X
- X CCRELEASE: copy on _r_e_l_e_a_s_e requests.
- X
- X CCHELP: copy on _h_e_l_p requests.
- X
- X CCERRORS: copy on various error conditions.
- X
- X CCALL: all of the above.
- X
- X
- X
- XAnastasios Kotsikonas 8
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X Manager preferences are optional.
- X
- X Owner privileges
- X Whenever an owner issues a user request on a user's
- X behalf (see below), all restrictions, including dis-
- X abled commands, do not apply. All other administrative
- X requests are subject to restrictions set by the
- X _m_a_n_a_g_e_r. All requests (user and administrative) are
- X subject to batch-processing.
- X
- X Administrative requests
- X The following requests may be issued by a list's owner:
- X
- X _s_y_s_t_e_m list password user-address #user-request
- X This request overrides all system restrictions and exe-
- X cutes _u_s_e_r-_r_e_q_u_e_s_t on behalf of _u_s_e_r-_a_d_d_r_e_s_s; this
- X address has to appear as listed in the ".subscribers"
- X file, where applicable. The most frequent use of the
- X _s_y_s_t_e_m request is to subscribe a user to a private
- X list. For example:
- X
- X system herc herc1 john@foo #subscribe herc Some Name
- X
- X If a _u_s_e_r-_r_e_q_u_e_s_t refers to a list, this list has to be
- X _l_i_s_t, so that a list's owner may not have privileges
- X over another list's affairs. Note that all replies
- X about _u_s_e_r-_r_e_q_u_e_s_t are forwarded to _u_s_e_r-_a_d_d_r_e_s_s, not
- X the owner; therefore, care has to be taken to avoid
- X syntax errors. The _s_y_s_t_e_m request is not subject to
- X restrictions, disabled requests, and private list sub-
- X scription verification (it is still subject to private
- X list review as outlined above, and batching). To remove
- X a member from his list, the owner may issue the follow-
- X ing request:
- X
- X system herc herc1 john@foo #unsubscribe herc
- X
- X To bypass restrictions and review his list, the owner
- X may issue the following:
- X
- X system venus venus1 his-address #review venus
- X
- X In general, _u_s_e_r-_r_e_q_u_e_s_t may be any of the recognized
- X user requests described under _l_i_s_t_p_r_o_c. The pound sign
- X is mandatory. There is no help available to users for
- X this request for security reasons.
- X
- X _a_p_p_r_o_v_e list password tag
- X Whenever a new message arrives for a moderated list a
- X copy is sent to the list's owner soliciting his appro-
- X val -- proper instructions for approving or discarding
- X a message are included. This request approves the
- X
- X
- X
- XAnastasios Kotsikonas 9
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X message identified by the _t_a_g number for posting to
- X _l_i_s_t. The tag number is provided to the list's owner by
- X _l_i_s_t_p_r_o_c and is unique.
- X
- X _d_i_s_c_a_r_d list password tag
- X In contrast to the above request, this discards the
- X message identified by _t_a_g. Messages that are not
- X approved or discarded remain in the list's _m_o_d_e_r_a_t_e_d
- X file (see _l_i_s_t(1)).
- X
- X _r_e_p_o_r_t_s list password
- X Obtain all reports pertinent to _l_i_s_t; this will send
- X two mail messages: one with the current report
- X (HOMEDIR/lists/ALIAS/.report.list), and one with the
- X previously archived ones
- X (HOMEDIR/lists/ALIAS/.rep.list.acc); see the REPORTS
- X section below. Once the ".rep.list.acc" file is sent,
- X it is shrunk in size, therefore the owner should make
- X sure he keeps the copy he receives.
- X
- X This request has no effect if the system is using sys-
- X log(3) to generate reports.
- X
- X _e_d_i_t list password file
- X Obtain the specified _f_i_l_e for editing; candidate files
- X are:
- X
- X _a_l_i_a_s_e_s: obtain the list's aliases file.
- X
- X _i_g_n_o_r_e_d: obtain the list's list of unwelcome
- X addresses.
- X
- X _i_n_f_o: obtain the list's informative message.
- X
- X _s_u_b_s_c_r_i_b_e_r_s: obtain the list's subscribers list.
- X
- X _w_e_l_c_o_m_e: obtain the list's welcoming message.
- X
- X _n_e_w_s: obtain the list's list of newsgroup connec-
- X tions.
- X
- X _p_e_e_r_s: obtain the list's peers.
- X
- X _p_u_t list password keyword [args]
- X This enables the list's owner to append to the
- X ".aliases" and ".ignored" files, and replace his list's
- X ".welcome", ".info", ".aliases", ".ignored", ".sub-
- X scribers", ".news" and ".peers" files, depending on the
- X _k_e_y_w_o_r_d. Valid _k_e_y_w_o_r_ds are:
- X
- X _a_l_i_a_s: Add a user address alias to the list's and
- X system's ".aliases" files (see .ALIASES below). This
- X
- X
- X
- XAnastasios Kotsikonas 10
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X requires the new address and the address used for
- X subscription as arguments:
- X
- X put <list> <password> alias <new-alias> <address-as-
- X subscribed>
- X
- X For example:
- X
- X put venus venus1 alias foo!john john@foo
- X
- X _i_g_n_o_r_e: Add a user address to the list's ".ignore"
- X file only. Of course this address has to be provided
- X as argument:
- X
- X put <list> <password> ignore <address-as-subscribed-
- X or-aliased>
- X
- X For example:
- X
- X put ermis ermis1 ignore jack@foo
- X put ermis ermis1 ignore foo!jack
- X
- X _w_e_l_c_o_m_e,
- X _i_n_f_o,
- X _a_l_i_a_s_e_s,
- X _i_g_n_o_r_e_d,
- X _s_u_b_s_c_r_i_b_e_r_s,
- X _n_e_w_s,
- X _p_e_e_r_s: Create a new system file.
- X
- X For example:
- X
- X put <list> <password> subscribers
- X tasos ACK PASSWORD NO Tasos Kotsikonas
- X john NOACK PASS1 NO John Doe
- X
- X No arguments are needed. The text that is to go to
- X the corresponding file starts at the line following
- X this request and spans till the end of the mail mes-
- X sage. Thus, no more requests can be made in the same
- X mail message -- they are treated as regular text;
- X signature lines also signify the end of text, pro-
- X vided they start with "--" in a single line.
- X
- X A confirmation is sent to the owner once a _p_u_t request
- X is successfully processed.
- X
- XOOOOWWWWNNNNEEEERRRRSSSS
- X The format of the _o_w_n_e_r_s file is as follows:
- X
- X One entry per line; each entry is the full email address of
- X a list's owner, followed by the list alias he owns, followed
- X
- X
- X
- XAnastasios Kotsikonas 11
- X
- X
- X
- X
- X
- X
- Xlistproc(1) USER COMMANDS listproc(1)
- X
- X
- X
- X by any optional preferences. If the keyword _s_e_r_v_e_r is speci-
- X fied in place of the list alias, then preferences are
- X defined for the _m_a_n_a_g_e_r.
- X
- XSSSSEEEEEEEE AAAALLLLSSSSOOOO
- X catmail(1), farch(1), list(1), queue(1), server(1), ser-
- X verd(1), start(1)
- X
- XAAAAUUUUTTTTHHHHOOOORRRR
- X Anastasios C. Kotsikonas
- X Copyright (c) 1991-93, Anastasios Kotsikonas
- X Comments to tasos@cs.bu.edu
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- XAnastasios Kotsikonas 12
- X
- X
- X
- *-*-END-of-doc/listproc.nr-*-*
- echo x - doc/queue.nr
- sed 's/^X//' >doc/queue.nr <<'*-*-END-of-doc/queue.nr-*-*'
- X
- X
- X
- Xqueue(1) USER COMMANDS queue(1)
- X
- X
- X
- XNNNNAAAAMMMMEEEE
- X qqqquuuueeeeuuuueeeedddd - ListProcessor mail queue daemon
- X
- XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
- X qqqquuuueeeeuuuueeeedddd <ffffrrrreeeeqqqquuuueeeennnnccccyyyy>
- X
- XNNNNAAAAMMMMEEEE
- X ppppqqqquuuueeeeuuuueeee - process the specified mail queue files
- X
- XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
- X ppppqqqquuuueeeeuuuueeee [----eeee] [----DDDD] <ffffiiiilllleeeessss>
- X
- XOOOOVVVVEEEERRRRVVVVIIIIEEEEWWWW
- X This part of the ListProcessor system can be employed only
- X when using the _s_y_s_t_e_m mailmethod (see _s_e_r_v_e_r(1)). Messages
- X and replies to requests not delivered due to network prob-
- X lems are queued by the system in the directory
- X HOMEDIR/mqueue. This part of the system attempts periodic
- X redelivery of these files. If problems still persist, files
- X (messages) that cannot be delivered are requeued.
- X
- XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN:::: qqqquuuueeeeuuuueeeedddd
- X This is the daemon that looks for files in the mail queue.
- X It uses _p_q_u_e_u_e for redelivery. The queue is checked every
- X _f_r_e_q_u_e_n_c_y seconds. Whenever an error occurs with _p_q_u_e_u_e,
- X _q_u_e_u_e_d sends a mail message to _m_a_n_a_g_e_r (as defined in the
- X _c_o_n_f_i_g file) and aborts.
- X
- X _q_u_e_u_e_d is not spawned by _s_t_a_r_t(1) in order to reduce the
- X number of processes running, since the probability of mes-
- X sages being queued is very low. Instead, it should be
- X started manually whenever there are files in the mail queue
- X directory.
- X
- XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN:::: ppppqqqquuuueeeeuuuueeee
- X The _f_i_l_e_s given as arguments are redelivered. If any of
- X these cannot be redelivered, they are requeued and will be
- X processed in the next run. _p_q_u_e_u_e reports to the file
- X HOMEDIR/.report.pqueue
- X
- X The following command line options are recognized:
- X
- X -e Echo reports to the screen; it has no effect if the
- X system has been compiled with -DSYSLOG.
- X
- X -D Turns debugging on; a copy of the last SMTP transaction
- X can be found in the files HOMEDIR/sent and
- X HOMEDIR/received. Warning: these files are also used by
- X _l_i_s_t(1) and _l_i_s_t_p_r_o_c(1) when they have their debug mode
- X on, so use caution.
- X
- X
- X
- X
- X
- XAnastasios Kotsikonas 1
- X
- X
- X
- X
- X
- X
- Xqueue(1) USER COMMANDS queue(1)
- X
- X
- X
- XNNNNOOOOTTTTEEEE
- X This mail queueing system should not be confused with the
- X one implemented by sendmail(1).
- X
- XSSSSEEEEEEEE AAAALLLLSSSSOOOO
- X server(1)
- X
- XAAAAUUUUTTTTHHHHOOOORRRR
- X Anastasios C. Kotsikonas
- X Copyright (c) 1991-93, Anastasios Kotsikonas
- X Comments to tasos@cs.bu.edu
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- XAnastasios Kotsikonas 2
- X
- X
- X
- *-*-END-of-doc/queue.nr-*-*
- echo x - doc/server.nr
- sed 's/^X//' >doc/server.nr <<'*-*-END-of-doc/server.nr-*-*'
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- XNNNNAAAAMMMMEEEE
- X ListProcessor version 6.0
- X
- XOOOOVVVVEEEERRRRVVVVIIIIEEEEWWWW
- X This is a system that implements various mailing lists with
- X one list manager. It is automated, and obliterates the need
- X for user intervention and maintenance of multiple aliases of
- X the form "list, list-owner, list-request", etc. There is
- X support provided for public and private hierarchical
- X archives, moderated and non-moderated lists, peer lists,
- X peer servers, private lists, address aliasing, news connec-
- X tions and gateways, mail queueing, digests, list ownership,
- X owner preferences, crash recovery, batch processing, confi-
- X gurable headers, regular expressions, archive searching, and
- X live user connections via TCP/IP.
- X
- XOOOOBBBBTTTTAAAAIIIINNNNIIIINNNNGGGG IIIINNNNFFFFOOOORRRRMMMMAAAATTTTIIIIOOOONNNN
- X mailing lists, aliases, news groups, peer lists
- X See list(1).
- X
- X user requests, list owners, peer servers, remote lists
- X See listproc(1).
- X
- X distributing incoming mail
- X See catmail(1).
- X
- X archiving files
- X See farch(1).
- X
- X archiving of lists' messages
- X See below.
- X
- X processing the mail queue
- X See queue(1).
- X
- X options for the system's daemon
- X See serverd(1).
- X
- X starting and stopping the system
- X See start(1).
- X
- X live connections
- X See ilp(1) and serverd(1).
- X
- XSSSSYYYYSSSSTTTTEEEEMMMM SSSSEEEETTTTUUUUPPPP
- X The ListProcessor system is installed under the HOMEDIR
- X directory as defined in src/Makefile; HOMEDIR points to the
- X top level directory of the installation; a _s_e_r_v_e_r user
- X account has to be setup. The system should be installed and
- X set up using this account, and always be started from this
- X account as well (see _s_t_a_r_t(1)). Then, the following alias
- X has to be defined in /etc/aliases, /usr/lib/aliases or
- X
- X
- X
- XKubota Computer 1
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X /usr/ucblib/aliases (depending on your system) for listpro-
- X cessor (where users send their requests):
- X
- X listproc: "|HOMEDIR/catmail -r -f"
- X
- X Various mailing lists are set up in a similar fashion; see
- X _l_i_s_t(1).
- X
- X It is important to keep in mind that mailers should convert
- X any text lines (not header lines) of incoming messages
- X starting with "From ", to ">From ". This is automatically
- X done by the -f flag to _c_a_t_m_a_i_l(1).
- X
- X The _c_a_t_m_a_i_l(1) utility is used to append incoming mail to
- X the appropriate files. When properly set up, it has the
- X setuid bit turned on. Since execute permission is granted to
- X everybody, it is possible for anyone to append to these
- X files; however, each time _c_a_t_m_a_i_l(1) is run, it reports the
- X user id and user name whom access was granted to.
- X
- X If the system is to go interactive (see _s_e_r_v_e_r_d(1)), you
- X have to add the following line in your /etc/services file:
- X
- X ulistproc 372/tcp
- X
- X See also src/Makefile.
- X
- X How the system operates is defined in the _c_o_n_f_i_g file (see
- X below). Once the system is loaded, you will have to run the
- X script _s_e_t_u_p; this will ensure that all necessary files and
- X directories are present, and have the right permissions.
- X Before starting the system, you may wish to edit the
- X ".ignored" file in HOMEDIR (see _l_i_s_t(1)). At this point,
- X you may also wish to alter the help files in HOMEDIR/help;
- X each file in that directory corresponds to one of the recog-
- X nized requests. Help files may be simple text files, or
- X shell scripts starting with "#!" in the first line, fol-
- X lowed by the shell to execute.
- X
- X File protections are a major issue and the requirements may
- X vary from system to system. The problems usually arise from
- X inadequate write permissions while appending mail to the
- X various mail files. The system uses the environment variable
- X ULISTPROC_UMASK in the same way as umask(1) is used when
- X updating files. If not set, the default is 066. A value of
- X 026 should be acceptable in most cases. This variable should
- X be set in both .cshrc and .profile. For archived files, you
- X may use the ULISTPROC_ARCHIVES_UMASK variable, which
- X defaults to the value set for ULISTPROC_UMASK.
- X
- X Finally, experiment with the various mail methods described
- X below, until you get the proper "From " line in the
- X
- X
- X
- XKubota Computer 2
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X beginning of the outgoing message; for instance, when _l_i_s_t_-
- X _p_r_o_c(1) is replying to a request, you should see something
- X like "From listproc@your-domain" as the first line of the
- X header; or when the list abc is distributing messages, this
- X line should look like "From abc@your-domain". If you cannot
- X get it to work, i.e. you get something like "From
- X server@your-domain" then the server system may have to run
- X with superuser privileges. In this case, the server userid
- X should be the same as root's. Also consult the PORT SPECIFIC
- X section below, for suggested mailmethods. You will not have
- X any of these problems if you use the _s_y_s_t_e_m mailmethod (see
- X below).
- X
- X If this part of the setup is not done properly, peer lists
- X will not work at all and users may not be able to reply to
- X the list. As a final note, if _t_e_l_n_e_t does not seem to be
- X sending any mail, it is a bug with the telnet implementation
- X on your system: telnet cannot have its input redirected or
- X piped, and should be reported to your vendor.
- X
- X The last step for a complete set up is to define your system
- X in the _c_o_n_f_i_g file.
- X
- XCCCCOOOONNNNFFFFIIIIGGGG
- X The server system is defined in the _c_o_n_f_i_g file; an example
- X file is provided with the system. This file is used by
- X _s_t_a_r_t(1), _s_e_r_v_e_r_d(1), _l_i_s_t(1) and _l_i_s_t_p_r_o_c(1), and is not a
- X shell script.
- X
- X The following keywords (directives) are recognized and is
- X advisable that each one of them starts at column 1; direc-
- X tives may span multiple lines if each line is terminated by
- X &\n:
- X
- X _o_r_g_a_n_i_z_a_t_i_o_n name
- X This defines your organization when posting to news and
- X upon connection establishment of a live session. _n_a_m_e
- X may include blanks.
- X
- X _s_e_r_v_e_r _l_i_s_t_p_r_o_c@your-domain command-line-options
- X This defines the list processor; the first argument is
- X the full email address of the server (e.g.
- X listproc@foo.edu) followed by any command line options
- X to be used when _s_e_r_v_e_r_d spawns _l_i_s_t_p_r_o_c (see _s_e_r_-
- X _v_e_r_d(1), _l_i_s_t_p_r_o_c(1)).
- X
- X _l_i_s_t list_alias email-addr owner-addr password cmd-line-opt
- X This defines a mailing list; the first argument is the
- X list's alias in /etc/aliases, /usr/lib/aliases or
- X /usr/ucblib/aliases (see _l_i_s_t(1)), followed by its full
- X email address, followed by its owner's full email
- X address, followed by the list's password for
- X
- X
- X
- XKubota Computer 3
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X maintenance, followed by any command line options to be
- X used when _s_e_r_v_e_r_d(1) spawns _l_i_s_t(1).
- X
- X _h_e_a_d_e_r list { [Header-Line:] ... }
- X It specifies precious header lines from the original
- X sender's message that are to be preserved during dis-
- X tribution. The _l_i_s_t has to be defined before, and pre-
- X cious header lines are specified within the enclosing {
- X and }, possibly spanning multiple lines.
- X
- X _d_e_f_a_u_l_t list { [option = value] ... }
- X Determine various default values for _l_i_s_t for new and
- X current subscribers; the list has to be defined before.
- X Pairs of options and values may be repeated any number
- X of times, and may span multiple lines; if certain
- X options are missing, then system defaults are used.
- X Valid _o_p_t_i_o_ns are:
- X
- X _a_d_d_r_e_s_s: turn user-settable subscription addresses on
- X or off. Valid values are:
- X
- X _f_i_x_e_d: users are not allowed to change the address
- X they are subscribed with via the _s_e_t <_l_i_s_t> _a_d_d_r_e_s_s
- X request (see _l_i_s_t_p_r_o_c(1)). This is the system
- X default as well.
- X
- X _v_a_r_i_a_b_l_e: opposite of the above.
- X
- X _m_a_i_l: select the default mail mode for new sub-
- X scribers. Valid values are:
- X
- X _a_c_k: see _s_e_t in _l_i_s_t_p_r_o_c(1).
- X
- X _n_o_a_c_k: see _s_e_t in _l_i_s_t_p_r_o_c(1); this is the system
- X default.
- X
- X _p_o_s_t_p_o_n_e: see _s_e_t in _l_i_s_t_p_r_o_c(1) (a rather useless
- X setting indeed).
- X
- X _d_i_g_e_s_t: see _s_e_t in _l_i_s_t_p_r_o_c(1).
- X
- X _p_a_s_s_w_o_r_d: define a single password for new users; if
- X missing, the system assigns a random password. Any
- X string that contains no white spaces may be used.
- X
- X _c_o_n_c_e_a_l: determine the default visibility of new
- X users; see _s_e_t in _l_i_s_t_p_r_o_c(1). Valid options are:
- X
- X _y_e_s: hidden from _r_e_c_i_p_i_e_n_t_s and _s_t_a_t_i_s_t_i_c_s
- X requests.
- X
- X _n_o: this is the system default.
- X
- X
- X
- XKubota Computer 4
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X _c_e_i_l_i_n_g list max_messages
- X Restrict the number of messages processed daily for
- X _l_i_s_t to _m_a_x__m_e_s_s_a_g_e_s; this includes posted and rejected
- X messages.
- X
- X _r_e_m_o_t_e alias email-addr listproc-addr [host [port]] #Comment
- X This makes a remote list known to the server. A remote
- X list is another mailing list served by another server,
- X and your server is now capable of forwarding to the
- X proper remote list processor any requests sent about
- X this remote list to your server. _a_l_i_a_s is the name by
- X which the remote list is known by, _e_m_a_i_l-_a_d_d_r is the
- X full email address of the remote list, _l_i_s_t_p_r_o_c-_a_d_d_r is
- X the full email address of the remote list processor,
- X and #_C_o_m_m_e_n_t will be used upon a _l_i_s_t_s request made to
- X this server (the pound sign is mandatory). _h_o_s_t is
- X either the DNS name or IP address of the remote server,
- X used to connect to that server when a live request
- X refers to that list; the _p_o_r_t should be specified if
- X not the default (372) (see _s_e_r_v_e_r_d(1)).
- X
- X Remote lists may have the same _a_l_i_a_s and they should
- X not be confused with peer lists. However, each remote
- X list should be defined only once. See the discussion
- X about PEER SERVERS (_l_i_s_t_p_r_o_c(1)) for further informa-
- X tion.
- X
- X _f_a_x fax-program options
- X Define the fax program to use for _f_a_x requests (if any)
- X and any command line options the program may use. The
- X program should also be capable of accepting the file to
- X fax from its standard input; otherwise a script will
- X have to be used instead which will in turn use the fax
- X program appropriately. If this directive is left or
- X commented out, then _f_a_x requests are automatically
- X turned off.
- X
- X The actual faxing program is called as follows:
- X
- X _f_a_x-_p_r_o_g_r_a_m _o_p_t_i_o_n_s fax-number < file
- X
- X This request may not be issued from a live session,
- X since fax programs work on email messages and extract
- X the sender's address for reference when sending the
- X cover page of the fax.
- X
- X _u_n_i_x__c_m_d list_alias password name 'unix-command [args]'
- X #Comment
- X Allow a _l_i_s_t__a_l_i_a_s's subscribers only to execute the
- X above _u_n_i_x-_c_o_m_m_a_n_d aliased to _n_a_m_e. The _p_a_s_s_w_o_r_d is
- X made known to users who are to be given this privilege.
- X The oprional _a_r_g_s may be literal arguments to the
- X
- X
- X
- XKubota Computer 5
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X command as well as the special sequences $_n, where _n is
- X a digit from 1 to 9, or *; their meaning is that of the
- X Bourne shell, and they will be substituted by the
- X user's actual arguments. For example:
- X
- X unix_cmd ermis pass1 swap '/bin/echo $2 $1' #Syntax: swap <arg1> <arg2>
- X
- X will swap the user's first and second arguments. The
- X user would submit a request that could look like this:
- X
- X run ermis pass1 swap arg1 arg2
- X
- X No security checks are made except to ensure that the
- X arguments contain no `, |, :, < and >, so the _m_a_n_a_g_e_r
- X is encouraged to review and verify the proper function-
- X ing of _u_n_i_x-_c_o_m_m_a_n_d. The _C_o_m_m_e_n_t is used when users
- X issue 'run <list>' query requests.
- X
- X _s_e_r_v_e_r_d command-line-options
- X This defines the command line options that _s_t_a_r_t(1) is
- X to use when spawning _s_e_r_v_e_r_d(1).
- X
- X _r_e_s_t_r_i_c_t_i_o_n nusers
- X If a restriction is placed on a ListProcessor request
- X (via a -r command line option to _l_i_s_t_p_r_o_c(1)), this
- X directive defines the threshold number of users, above
- X which the restriction will take effect.
- X
- X _d_i_s_a_b_l_e list_alias request
- X The specified server _r_e_q_u_e_s_t is disabled for the speci-
- X fied list, and all such requests for this list are
- X rejected, except when issued by privileged users (list
- X owners). The _l_i_s_t__a_l_i_a_s has to be defined (via a _l_i_s_t
- X directive) before any requests can be disabled.
- X
- X _m_a_n_a_g_e_r full-email-address
- X This defines the recipient of all system error mes-
- X sages, and the system's administrator and caretaker;
- X _f_u_l_l-_e_m_a_i_l-_a_d_d_r_e_s_s can be any valid user name that can
- X be reached via email by your system. The _m_a_n_a_g_e_r is
- X usually the person responsible for the server account.
- X
- X _c_o_m_m_e_n_t _s_e_r_v_e_r #Actual comment
- X
- X _c_o_m_m_e_n_t list_alias #Actual comment
- X A 'X-Comment:' line is included in every outgoing
- X list/server message, and the text following the pound
- X sign will be copied every time; note that the pound
- X sign is mandatory for the definition but will not be
- X part of the actual string. A list's comment is also
- X used for the _l_i_s_t_s request to specify the purpose of
- X the particular mailing list. No 'X-Comment:' line is
- X
- X
- X
- XKubota Computer 6
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X included if this directive is not defined for the par-
- X ticular list and/or server.
- X
- X _d_i_g_e_s_t list_alias lines hours
- X If any subscriber to the list requests digests, a dig-
- X est will be sent when its length exceeds _l_i_n_e_s, or when
- X _h_o_u_r_s have passed without a digest being sent. Digests
- X for a list are collected only if at least one of its
- X subscribers has set his mail mode to _d_i_g_e_s_t.
- X
- X _a_r_c_h_i_v_e list_alias dir filename [archive] [password] [dig-
- X est]
- X Request that all public messages are automatically
- X archived; _l_i_s_t__a_l_i_a_s is the list's name, _d_i_r is the
- X directory that the archived files will be located (a
- X full path has to be specified, and the directory has to
- X be writable by the server uid), _a_r_c_h_i_v_e is the
- X archive's name and is a relative path under the default
- X archive (listproc) or "-" for the default, _p_a_s_s_w_o_r_d is
- X an optional password ("-" if none) to be used if the
- X archive is meant to be private, and the optional key-
- X word _d_i_g_e_s_t will force only digests to be archived;
- X _f_i_l_e_n_a_m_e specifies the format of the archived files,
- X and may contain any lower case characters and numbers,
- X as well as the following special sequences:
- X
- X %m: Numeric month (01 - 12)
- X
- X %d: Numeric day of the month (01 - 31)
- X
- X %y: Year (00 - 99)
- X
- X %j: Julian date (001 - 366)
- X
- X %h: Month name (Jan - Dec)
- X
- X %a: Contents of the Archive-Name: header line, if
- X present; cannot be used if archiving digests. The
- X Archive-Name: header line has to be manually inserted
- X by the sender of the message; it may show up in the
- X body of the message as well.
- X
- X %#: Digest number; can only be used if archiving dig-
- X ests.
- X
- X %1: First word of the first non-blank line of the
- X message.
- X
- X %v: Volume number, if the message contains a 'Volume
- X # Number #' line before the actual message.
- X
- X %n: Issue number, if the message contains a 'Volume #
- X
- X
- X
- XKubota Computer 7
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X Number #' line before the actual message.
- X
- X %%: The character %
- X
- X For example, to archive messages daily:
- X
- X archive ermis HOMEDIR/archives/lists/ermis %y%m%d listproc/lists/ermis
- X
- X or to archive only files sent to the list:
- X
- X archive venus /ftp/lists/venus vol-%v.num-%n listproc/lists/venus johny-be-good
- X
- X and in this case the sender that wants a file to be
- X archived would precede it with a line similar to:
- X
- X Volume 10 Number 5
- X
- X followed by the actual file.
- X
- X When a new archive file is created, the Subject: line
- X is used as the short descriptive message for the
- X archive.
- X
- X _f_r_e_q_u_e_n_c_y seconds
- X How often should _s_e_r_v_e_r_d(1) check for new mail. When
- X _s_e_c_o_n_d_s is set to zero, _s_e_r_v_e_r_d does not sleep.
- X
- X _b_a_t_c_h start stop
- X Specify the hours (in military time) when requests are
- X to be batched. The defaults are 8 and 20. _s_t_a_r_t and
- X _s_t_o_p should be within the same day (e.g. 8 am and 1 am
- X the following day are not valid).
- X
- X _l_i_m_i_t keyword arguments
- X Used to set certain limits in the system; _k_e_y_w_o_r_d can
- X be:
- X
- X _m_e_s_s_a_g_e: limit the size of distributed messages to a
- X certain number of bytes, which is the _a_r_g_u_m_e_n_t fol-
- X lowing this keyword. A notification is sent back to
- X the sender when this limit is exceeded, including the
- X first few lines of his/her original message for
- X reference.
- X
- X _f_i_l_e_s: limit the size of archive files that can be
- X sent out to a certain number of bytes, which is the
- X _a_r_g_u_m_e_n_t following this keyword. When this limit is
- X reached, the file is automatically split into sub-
- X parts.
- X
- X _p_r_e_c_e_d_e_n_c_e string
- X The header of each outgoing message contains a
- X
- X
- X
- XKubota Computer 8
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X Precedence: line; _s_t_r_i_n_g can be:
- X
- X bulk, junk, first-class, none: primarily used for
- X vacation programs.
- X
- X _o_p_t_i_o_n keyword
- X This defines a series of system-dependent options; _k_e_y_-
- X _w_o_r_d can be:
- X
- X _s_y_s_v__p_s: the system will assume a System V version of
- X ps(1).
- X
- X _b_s_d__p_s: the system will assume a BSD version of
- X ps(1).
- X
- X _b_s_d__m_a_i_l: define it if BSD (UCB) mail is available on
- X your system; if this is the case, make sure that
- X /usr/ucb/mail is the path (or a link) to it; also see
- X src/Makefile. This is used to notify the _m_a_n_a_g_e_r of
- X any error conditions.
- X
- X _b_a_d__t_e_l_n_e_t: if the mail method used (see below) is
- X _t_e_l_n_e_t and the system seems to send out only one mes-
- X sage and then go to sleep, use this option.
- X
- X _p_o_s_t__m_a_i_l: this will force the system to post mes-
- X sages to news groups (using _i_n_e_w_s), using the groups'
- X names (e.g. misc.test). Make sure that _i_n_e_w_s resides
- X in /usr/lib/news, or /usr/lib/news/inews is a link to
- X it (also see src/Makefile).
- X
- X _g_a_t_e__m_a_i_l: this will force the system to gate mes-
- X sages to news, using the gateways' email addresses.
- X
- X _i_g_n_o_r_e__i_n_v_a_l_i_d__r_e_q_u_e_s_t_s: ignore all unrecognized user
- X requests and process valid ones only; by default, the
- X system aborts processing requests upon the first
- X invalid one, in which case a reply is sent to the
- X user and all subsequent requests are flushed.
- X
- X _r_e_l_a_x_e_d__s_y_n_t_a_x: by default, the system complains when
- X a request is given more arguments than expected. This
- X turns such checking off.
- X
- X _m_a_i_l_m_e_t_h_o_d method [arguments]
- X Every outgoing message should begin with a line of the
- X form:
- X
- X From listproc@your-domain
- X
- X or
- X
- X
- X
- X
- XKubota Computer 9
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X From list_alias@your-domain
- X
- X which depends on the mail _m_e_t_h_o_d used:
- X
- X _s_y_s_t_e_m: the recommended method; it provides a unified
- X approach to sending mail and it has been ported and
- X tested on lots of systems (see the section
- X PORT SPECIFIC below). In addition, since a full set
- X of the SMTP protocol is implemented, _m_a_n_a_g_e_r and list
- X owners will be notified of invalid addresses and
- X various system problems. Moreover, mail will be
- X queued when it cannot be delivered, in the directory
- X HOMEDIR/mqueue; see _q_u_e_u_e(_1) for more information on
- X how to process the mail queue.
- X
- X This method requires host TCP/IP and internet sup-
- X port; consult the src/README file for more informa-
- X tion.
- X
- X _t_e_l_n_e_t: to be used only when _s_y_s_t_e_m is inappropriate
- X and telnet(1) is available on your host.
- X
- X _e_n_v__v_a_r: usually followed by _L_O_G_N_A_M_E /_b_i_n/_r_m_a_i_l, or
- X _L_O_G_N_A_M_E /_u_s_r/_l_i_b/_s_e_n_d_m_a_i_l -_b_a (-ba is mandatory) --
- X to be used only when the previous methods are inap-
- X propriate.
- X
- XMMMMAAAAIIIILLLL LLLLOOOOOOOOPPPPSSSS
- X The system uses the following protocol for avoiding mail
- X loops between a list and news connections: In the header of
- X the outgoing message an "Originator: " field is added. For
- X each list plus listproc, a log of the most recent (500)
- X Message-Id's is kept. Whenever a message is received, the
- X Originator, Reply-To and Message-Id fields are extracted and
- X looked up in the ".ignored" and ".message.ids" files in the
- X list's subdirectory. Gateways that feed back to the list
- X should preserve at least the Reply-To and Message-Id fields.
- X The Originator and Message-Id fields are preserved by this
- X system. A new Reply-To is tacked on when redistributing mail
- X locally from a peer or a news feed.
- X
- X To avoid mail loops when forwarding ListProcessor requests
- X to peers, the system looks up the Message-Id field in the
- X ".message.ids" file in HOMEDIR. If this field is not
- X preserved by the peer ListProcessor, it is suggested that
- X you turn off request forwarding when connecting with peers
- X served by such systems, until a unified approach is taken.
- X The Message-Id field is preserved by this ListProcessor.
- X This system is also using a special Subject field, totally
- X proprietary and non-standard, in order to avoid unnecessary
- X forwarding of requests, thus cutting down on email traffic.
- X
- X
- X
- X
- XKubota Computer 10
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X In addition, the system searches incoming messages for
- X Message-Ids in the message body, as well as the occurence of
- X the X-Listprocessor-Version header line in it, since most
- X bounced messages include the entire original message.
- X
- X Finally, a checksum for each incoming message is obtained
- X and looked up against a database of the 500 most recent sums
- X in the file ".sums" in the list's subdirectory.
- X
- XCCCCRRRRAAAASSSSHHHH RRRREEEECCCCOOOOVVVVEEEERRRRYYYY
- X It is possible that a message delivery was interrupted by a
- X user (_s_t_a_r_t -_k), or by the system (crash/reboot). A built-in
- X mechanism guarrantees to pick up delivery again from where
- X it left off, if the system is restarted using _s_t_a_r_t(1). Both
- X _s_t_a_r_t(1) and _l_i_s_t(1) report to the effect that mail delivery
- X was interrupted and will resume. On the other hand, process-
- X ing of interrupted requests will not resume and all unpro-
- X cessed requests will be lost.
- X
- XCCCCOOOOMMMMMMMMUUUUNNNNIIIICCCCAAAATTTTIIIINNNNGGGG
- X Users send requests to _l_i_s_t_p_r_o_c@_y_o_u_r-_d_o_m_a_i_n and public mes-
- X sages to the various _l_i_s_t__a_l_i_a_s@_y_o_u_r-_d_o_m_a_i_n.
- X
- XAAAARRRRCCCCHHHHIIIIVVVVEEEESSSS
- X The server has an archiving capability of files. Archives
- X may be public so that anyone can get files from them, or
- X private so that only privileged users may obtain files from
- X them. There is a master archive in HOMEDIR/archives/listproc
- X where all subarchives are defined. The archives keep lists
- X of files that are available to users via a _g_e_t request, and
- X index of subarchives that are available to users via an
- X _i_n_d_e_x request.
- X
- X As outlined in _l_i_s_t(1), each list's public messages are
- X automatically saved under the list's subdirectory in the
- X file _a_r_c_h_i_v_e. This file may periodically be placed in the
- X system's archives by hand (if not archiving automatically
- X via the _a_r_c_h_i_v_e directive), or may point to /dev/null. The
- X archived files may not necessarily reside in the archive
- X directories, as long as the archives know where they are
- X located. See the man page for _f_a_r_c_h(_1) for more information.
- X
- X Alternatively, messages may be automatically archived via
- X the _a_r_c_h_i_v_e directive in the _c_o_n_f_i_g file.
- X
- XHHHHEEEELLLLPPPP
- X The system comes configured with default help topics the
- X recognized requests. More topics may be added by editing the
- X file HOMEDIR/help/TOPICS, adding the topic(s) and the
- X file(s) where the actual text exists.
- X
- X
- X
- X
- X
- XKubota Computer 11
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X Help files may be simple text files or shell scripts, in
- X which case they have to start with "#!" in the first line
- X and be followed by the path to the shell to be used; for
- X example: #!/bin/sh
- X
- XSSSSYYYYSSSSTTTTEEEEMMMM MMMMAAAAIIIINNNNTTTTEEEENNNNAAAANNNNCCCCEEEE
- X As mentioned below, all programs report to certain files.
- X The system's manager should periodically check the files
- X HOMEDIR/.report.server and the various
- X HOMEDIR/lists/*/.report.list for any problems. All messages
- X sent are saved under HOMEDIR/mbox and HOMEDIR/lists/*/mbox
- X and they should be cleaned up periodically. For debugging
- X purposes, various warnings are written to HOMEDIR/.warning;
- X this file, as well as HOMEDIR/.report.catmail are shrunk
- X every time _s_t_a_r_t(1) is run.
- X
- X For whenever the necessity arises to administer the system
- X remotely, the following scheme may be used to start or kill
- X the system, process the mail queue, force an application to
- X execute immediately, etc: a mail message is sent to an alias
- X whose sole role is to fire up an application; the applica-
- X tion has to have been setuid before.
- X
- X For instance, to start the system remotely, you may set up
- X an alias such as:
- X
- X start-server: "|HOMEDIR/start -cr > /dev/null"
- X
- X To kill the system, you may define another alias:
- X
- X kill-server: "|HOMEDIR/start -crk > /dev/null"
- X
- X To force requests to get processed now:
- X
- X run-listproc: "|HOMEDIR/listproc -1 > /dev/null"
- X
- X To start the queue daemon:
- X
- X proc-queue: "|HOMEDIR/queued 60 & > /dev/null"
- X
- X These aliases should be hard to guess for obvious reasons.
- X The actual message sent to such an alias is discarded.
- X
- XEEEEXXXXIIIITTTT CCCCOOOODDDDEEEESSSS
- X All applications except tlock use the following exit codes
- X for communication:
- X
- X
- X 0 - OK, normal exit
- X
- X 1 - Could not open or lock file
- X
- X
- X
- X
- XKubota Computer 12
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X 2 - SIGINT signal (normal termination)
- X
- X 3 - Command line option error
- X
- X 4 - Syntax error in file
- X
- X 5 - Could not spawn (restart failed)
- X
- X 6 - Shutdown request
- X
- X 7 - Restart request
- X
- X 8 - Received system signal (anything but SIGINT will
- X bring the system down)
- X
- X 9 - Too many multiple recipients
- X
- X 10 - Could not deliver mail (unexpected reply during the
- X SMTP transaction)
- X
- X 11 - malloc() failed
- X
- X 12 - Cannot fork()
- X
- X 13 - Socket connection problem
- X
- X 14 - Semaphore error
- X
- X 15 - Cannot setuid()/setgid()
- X
- X 16 - Internal error or system call failure
- X
- X tlock exits with:
- X
- X -1 - File locking not functional
- X
- X 0 - No files locked
- X
- X 1 - Cannot open config
- X
- X 2 & up
- X - Number of files locked + 1
- X
- XRRRREEEEPPPPOOOORRRRTTTTSSSS
- X The system provides two ways of reporting progress: via sys-
- X log(3) when available (by compiling with -DSYSLOG=facility)
- X with priority LOG_INFO and facility as specified, or through
- X its own report files (when not using syslog(3)); these are:
- X
- X HOMEDIR/.report.catmail
- X Messages from _c_a_t_m_a_i_l(1) every time new messages are
- X appended to the various mail files.
- X
- X
- X
- XKubota Computer 13
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X HOMEDIR/.report.daemon
- X Messages from _s_e_r_v_e_r_d(1) every time new mail has
- X arrived.
- X
- X HOMEDIR/.report.list
- X Error messages from _l_i_s_t(1) when attempting to process
- X public messages.
- X
- X HOMEDIR/.report.pqueue
- X Messages from _p_q_u_e_u_e (see _q_u_e_u_e(1)).
- X
- X HOMEDIR/.report.server
- X Messages from _l_i_s_t_p_r_o_c(1) every time new requests are
- X processed.
- X
- X HOMEDIR/.report.start
- X Generated by _s_t_a_r_t(1) every time the system is started.
- X
- X HOMEDIR/lists/LIST_ALIAS/.report.list
- X Messages from _l_i_s_t(1) when processing public messages.
- X
- X HOMEDIR/.*.acc
- X Accumulated reports since the system was first
- X installed.
- X
- X HOMEDIR/lists/*/.*.acc
- X Accumulated reports for each mailing list.
- X
- X Every report includes a time stamp; every list and server
- X report also includes the actual sender of the message, and
- X every server report includes all requests made by the
- X sender.
- X
- X Whenever a program dies abnormally (and BSD mail is present)
- X a message is sent to _m_a_n_a_g_e_r (as defined in _c_o_n_f_i_g). The
- X message is usually sent by _s_e_r_v_e_r_d(1) which then exits. The
- X daemon dies with a different message according to the exit
- X status of the child; the various error conditions that may
- X occur are:
- X
- X Could not open file
- X HOMEDIR is not a valid path; file was accidentally
- X deleted; insufficient access privileges. Run _s_e_t_u_p and
- X _s_t_a_r_t.
- X
- X Could not lock file
- X HOMEDIR is not a valid path; file was accidentally
- X deleted; insufficient access privileges; another pro-
- X gram is using the lock file. Run _t_l_o_c_k, and if neces-
- X sary, _u_l_o_c_k; then _s_t_a_r_t. _t_l_o_c_k checks for locked
- X files, and _u_l_o_c_k removes all lock files.
- X
- X
- X
- X
- XKubota Computer 14
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X Command line option error
- X Check the _c_o_n_f_i_g file and restart.
- X
- X Syntax error in file
- X Check _c_o_n_f_i_g, all reports, .subscribers, .peers and
- X .news files.
- X
- X Could not spawn
- X No more processes.
- X
- X Received system signal
- X SIGQUIT, SIGTERM, SIGBUS, SIGSEGV, SIGILL.
- X
- XFFFFIIIILLLLEEEESSSS
- X HOMEDIR/.aliases
- X Aliases of email addresses of users having trouble get-
- X ting replies to requests.
- X
- X HOMEDIR/.awk
- X awk program for formatting the _s_t_a_t_i_s_t_i_c_s request.
- X
- X HOMEDIR/.grep
- X script used for counting the number of messages sent by
- X a subscriber.
- X
- X HOMEDIR/.ignored
- X List of unwanted senders.
- X
- X HOMEDIR/.lock.pqueue
- X Lock file for _p_q_u_e_u_e (see _q_u_e_u_e(1)).
- X
- X HOMEDIR/.lock.serverd
- X Lock file for _s_e_r_v_e_r_d(1).
- X
- X HOMEDIR/.message.ids
- X A database of recent message id's used to detect mail
- X loops.
- X
- X HOMEDIR/.queue.id
- X Next id to be assigned to next undeliverable message
- X placed in the mqueue/ directory.
- X
- X HOMEDIR/.reply.listser
- X The reply code given to _s_e_r_v_e_r_d(1) during a live ses-
- X sion.
- X
- X HOMEDIR/.rep.server.acc
- X Archived _l_i_s_t_p_r_o_c(1) reports.
- X
- X HOMEDIR/.rep.serverd.acc
- X Archived _s_e_r_v_e_r_d(1) reports.
- X
- X
- X
- X
- XKubota Computer 15
- X
- X
- X
- X
- X
- X
- Xserver(1) USER COMMANDS server(1)
- X
- X
- X
- X HOMEDIR/.rep.start.acc
- X Archived _s_t_a_r_t(1) reports.
- X
- X HOMEDIR/.report.catmail
- X Current _c_a_t_m_a_i_l(1) report.
- X
- X HOMEDIR/.report.daemon
- X Current _s_e_r_v_e_r_d(1) report.
- X
- X HOMEDIR/.report.list
- X